spring-projects / spring-statemachine

Spring Statemachine is a framework for application developers to use state machine concepts with Spring.
1.54k stars 607 forks source link

Acquire StateMachine is overwrite saved to DB state machine to initial state #1142

Open ksilisk opened 6 months ago

ksilisk commented 6 months ago

When using acquireStateMachine in DefaultStateMachineService the persisted machine to be overwritten with a new machine context before reaching the restore logic so the restored machine is always in the initial state.

After delving deeper into this, I found the source of the problem.

The problem lies in the fact that the AbstractStateMachineFactory overwrites the state of the machine when it is starting in delegateAutoStartup if the autoStartup property is true in this method. https://github.com/spring-projects/spring-statemachine/blob/3ad063a80646a1c9974560dcf91a40230338c693/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java#L363

At this moment all interceptors adding for every regions which correct. https://github.com/spring-projects/spring-statemachine/blob/3ad063a80646a1c9974560dcf91a40230338c693/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/AbstractStateMachineFactory.java#L347-L355

But later we have problems, because occur calling the function callPostStateChangeInterceptors in AbstractStateMachine after starting created statemachine. https://github.com/spring-projects/spring-statemachine/blob/3ad063a80646a1c9974560dcf91a40230338c693/spring-statemachine-core/src/main/java/org/springframework/statemachine/support/AbstractStateMachine.java#L956-L962

And finally in AbstractPersistingStateMachineInterceptor occur write initial state created in AbstractStateMachineFactory to DB. https://github.com/spring-projects/spring-statemachine/blob/3ad063a80646a1c9974560dcf91a40230338c693/spring-statemachine-core/src/main/java/org/springframework/statemachine/persist/AbstractPersistingStateMachineInterceptor.java#L78

Also, we can view this problem in Redis with MONITOR command.

screen

In the DefaultStateMachineService, the first command is create a new machine from the stateMachineFactory, and then restore it from the database, but at the time of creation the persisted state is overwritten to initial state. https://github.com/spring-projects/spring-statemachine/blob/3ad063a80646a1c9974560dcf91a40230338c693/spring-statemachine-core/src/main/java/org/springframework/statemachine/service/DefaultStateMachineService.java#L83-L105

I think reorder the command in acquireStateMachine in DefaultStateMachineService can solve this problem.

Tell me, can this problem be solved in a similar way? If yes, then I'm ready to start working on this task.

Thanks!)

ksilisk commented 6 months ago

For other developers facing the same problem, I found two ways how to solve this:

  1. Disable autoStartup property if it possible
  2. Implement your own implementation of the StateMachineService with a modified order of creating and restoring a machine from the DB
qdrin commented 6 months ago

Hello, I'm meeting the same thing. Restoring from 3 orthogonal regions lead to weird: "left" region is being restored normally to saved state, and two others - to initial states. I guess this issue was fixed a bit earlier in #998 but not released. I'd like to solve this problem anyway