Reputation: 21
I'm currently facing an issue with Spring State Machine in my project. The problem arises when I acquire the state machine for the second time after it has reached the end state (FINISHED in this example). Instead of retaining its end state, the state machine reverts back to the initial state (CREATED). This causes validation to fail when the state is checked on subsequent calls.
And here is validateSessionState method:
public void validateSessionState(Session session, SessionState state) {
StateMachine<SessionState, SessionEvent> stateMachine =
stateMachineService.acquireStateMachine(session.getId().toString());
if (!stateMachine.getState().getId().equals(state)) {
throw new IllegalStateException(
"Session with id: "
+ session.getId()
+ " is not "
+ state
+ " but "
+ stateMachine.getState().getId());
}
}
Calling this method for the first time validates fine but then validation fails and State Machine goes back to CREATED, persisting this state.
Here is configuration for Spring State Machine:
@Configuration
@EnableStateMachineFactory
@RequiredArgsConstructor
public class SessionStateMachineConfig
extends EnumStateMachineConfigurerAdapter<SessionState, SessionEvent> {
private final StateMachineRuntimePersister<SessionState, SessionEvent, String> persister;
@Override
public void configure(StateMachineStateConfigurer<SessionState, SessionEvent> states)
throws Exception {
states
.withStates()
.initial(SessionState.CREATED)
.end(SessionState.FINISHED)
.end(SessionState.EXPIRED)
.states(EnumSet.allOf(SessionState.class));
}
@Override
public void configure(
final StateMachineConfigurationConfigurer<SessionState, SessionEvent> config)
throws Exception {
config.withConfiguration().autoStartup(false);
config.withPersistence().runtimePersister(persister);
}
@Override
public void configure(StateMachineTransitionConfigurer<SessionState, SessionEvent> transitions)
throws Exception {
transitions
.withExternal()
.source(SessionState.CREATED)
.target(SessionState.ACTIVATED)
.event(SessionEvent.ACTIVATE)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.CREATED)
.target(SessionState.EXPIRED)
.event(SessionEvent.EXPIRE)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.ACTIVATED)
.target(SessionState.ANSWERING_COMMONS)
.event(SessionEvent.GET_COMMONS)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.ACTIVATED)
.target(SessionState.EXPIRED)
.event(SessionEvent.EXPIRE)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.ANSWERING_COMMONS)
.target(SessionState.ANSWERING_SKILL_SET)
.event(SessionEvent.GET_SKILL_SET)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.ANSWERING_COMMONS)
.target(SessionState.EXPIRED)
.event(SessionEvent.EXPIRE)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.ANSWERING_SKILL_SET)
.target(SessionState.PROCESSING_QUIZ)
.event(SessionEvent.GENERATE)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.ANSWERING_SKILL_SET)
.target(SessionState.EXPIRED)
.event(SessionEvent.EXPIRE)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.PROCESSING_QUIZ)
.target(SessionState.IN_PROGRESS)
.event(SessionEvent.START)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.PROCESSING_QUIZ)
.target(SessionState.EXPIRED)
.event(SessionEvent.EXPIRE)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.IN_PROGRESS)
.target(SessionState.PROCESSING_RESULTS)
.event(SessionEvent.SUBMIT)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.IN_PROGRESS)
.target(SessionState.EXPIRED)
.event(SessionEvent.EXPIRE)
.action(loggingAction())
.and()
.withExternal()
.source(SessionState.PROCESSING_RESULTS)
.target(SessionState.FINISHED)
.event(SessionEvent.FINISH)
.action(loggingAction());
}
@Bean
public StateMachineService<SessionState, SessionEvent> stateMachineService(
final StateMachineFactory<SessionState, SessionEvent> sessionStateMachineFactory,
final StateMachineRuntimePersister<SessionState, SessionEvent, String>
sessionsStateMachinePersist) {
return new DefaultStateMachineService<>(
sessionStateMachineFactory, sessionsStateMachinePersist);
}
@Bean
public Action<SessionState, SessionEvent> loggingAction() {
return new LoggingAction();
}
}
Has anyone encountered a similar issue with Spring State Machine? Any insights or suggestions on what might be going wrong here would be greatly appreciated.
Upvotes: 2
Views: 71