2

I am evaluating Spring Statemachine and would like to understand how to recover from a transition error.

I defined an error action for an action executed during a transition. The execution of S1_TO_S2_ACTION causes an exception which is handled in S1_TO_S2_ERROR_HANDLING.

I can handle the error in the action but how can I recover from the error? I tried to send an event in the error handler (context.getStateMachine().sendEvent(Events.RECOVER)) but without any effect.

@Configuration
@EnableStateMachine
class StateMachineConfig
    extends EnumStateMachineConfigurerAdapter<States, Events> {

    Action<States, Events> S1_TO_S2_ERROR_HANDLING = context -> {
        System.out.println(BO + " ERROR!!!");

        System.out.println("E: " + context.getException());
        System.out.println("S: " + context.getSource().getId());
        System.out.println("T: " + context.getTarget().getId());
    };


    @Override
    public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
        throws Exception {

        transitions
        .withExternal()
        .source(States.SI).target(States.S1).event(Events.E1)
        .action(TRANS_ACTION)
        .and()

        .withExternal()            
        .source(States.S1).target(States.S2).event(Events.E2)
        .action(S1_TO_S2_ACTION, S1_TO_S2_ERROR_HANDLING)
        .and()

        .withExternal()
        .source(States.S2).target(States.SE).event(Events.E3)
        .action(TRANS_ACTION);
    }
}

Suprisingly calling stateMachine.hasStateMachineError() afterwards returns false.

Who can I recover in an error action from an error and why does hasStateMachineError() returns false if an exception is thrown during a transition?

Oliver
  • 3,815
  • 8
  • 35
  • 63

2 Answers2

0

I reckon, you need to explicitly do:

try
    {
        ..
    }
    catch (WhateverException e)
    {
        stateMachine.setStateMachineError(e);
        throw e;
    }

Inside the statemachine transition functions.

I posted an answer to a different question, which may be relevant to you as well: https://stackoverflow.com/a/46519081/1258249

theAntonym
  • 39
  • 1
  • 8
0

Have you thought of putting a flag in the variables map in the extendedSstate of the StateContext, and retrieving it after an event has been processed? Then you can reset the state machine by getting the stateMachineAccess and calling resetStateMachine on it.

For example, in your S1_TO_S2_ERROR_HANDLING, you can do

context.getExtendedState().getVariables().put("recover", true);

Then, after you send an event to the state machine object, in your service layer maybe, check if its context variables contains a true recover flag, and reset it to the source state.

mave_rick
  • 59
  • 8