How to get exception thrown during state transition using spring state machine

Daniel :

I am trying to understand, how an exception thrown by an action during a state transition is possible. I‘ve this simple state machine configured:

transitions
    .withExternal()
    .source(State.A1)
    .target(State.A2)
    .event(Event.E1)
    .action(executeAnActionThrowingAnException())

In my service class, I injected my state machine and send this event E1:

@Service
public class MyService() {

    @Autowired
    private StateMachine<State, Event> stateMachine;

    public void executeMyLogic() {
        stateMachine.start()
        stateMachine.sendEvent(Event.E1);
        // how to get thrown exception here
    }
}

In my service I just want to know, if and why my state machine wasn‘t able to reached State.A2. Because a thrown exception is fetched by Spring state machine, I am not able to get any response after sending the event. But the state machine hasn‘t any error, which means that

stateMachine.hasStateMachineError()

will return false. So, how can I get the information in my service, that something went wrong and more importantly what?

I appriciate your help.

Best regards

hovanessyan :

For transitions exceptions, there's an overload for the actions method available in the TransitionConfigurer

action(Action<S,E> action, Action<S,E> error)

This means you can specify and additional action to be triggered, if there's an exception raised during the transition. The exception is available from the StateContext passed to the action.

When your error action is triggered, you can retrieve the exception with:

context.getException();

Inside the error action you can do a couple of things to deal with the exception:

  • do logging of the exception and the context
  • transition to some error state
  • clear the context and transition to the same state and try to execute some retry logic
  • add some additional info to the context and return the context to the caller

For example:

context.getVariables().put("hasError", true); 
context.getVariables().put("error", ex);

And in your service(caller) you handle the exception as you like, for example:

public void executeMyLogic() {
    stateMachine.start()
    stateMachine.sendEvent(Event.E1);
    if (stateMachine.getExtendedState().getVariables().containsKey("hasError") {
      throw (RuntimeException)stateMachine.getExtendedState().getVariables().get("error")
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=151780&siteId=1