spring-statemachine
spring-statemachine copied to clipboard
StateMachineRuntimePersister doesn't save/restore region states
I have the following StateMachine configuration:
@Configuration
open class PooledAppConfig {
@Bean
fun stateMachineRuntimePersister(
jpaStateMachineRepository: JpaStateMachineRepository): StateMachineRuntimePersister<String, String, String> {
return JpaPersistingStateMachineInterceptor<String, String, String>(jpaStateMachineRepository)
}
@Bean
fun stateMachineTarget(stateMachineRuntimePersister: StateMachineRuntimePersister<String, String, String>): StateMachine<String, String> {
val builder = StateMachineBuilder.builder<String, String>()
builder.configureConfiguration()
.withConfiguration()
.machineId("ItemSM")
builder.configureConfiguration()
.withPersistence()
.runtimePersister(stateMachineRuntimePersister)
builder.configureStates()
.withStates()
.initial("Init")
.state("S1")
.fork("FRK")
.state("GROUP")
.join("JN")
.and()
.withStates()
.parent("GROUP")
.region("R1")
.initial("F1I")
.state("F1S")
.end("F1E")
.and()
.withStates()
.parent("GROUP")
.region("R2")
.initial("F2I")
.state("F2S")
.end("F2E")
.and()
.withStates()
.parent("GROUP")
.region("R3")
.initial("F3I")
.state("F3S")
.end("F3E")
.and()
.withStates()
.state("END")
builder.configureTransitions()
.withExternal()
.source("Init").target("S1")
.event("E_IS1")
.and()
.withExternal()
.source("S1").target("FRK")
.event("E_FRK")
.and()
.withFork()
.source("FRK")
.target("GROUP")
.and()
.withJoin()
.source("GROUP")
.target("JN")
.and()
.withExternal()
.source("F1I").target("F1S")
.event("E_F1IS")
.and()
.withExternal()
.source("F2I").target("F2S")
.event("E_F2IS")
.and()
.withExternal()
.source("F3I").target("F3S")
.event("E_F3IS")
.and()
.withExternal()
.source("F1S").target("F1E")
.event("E_F1SE")
.and()
.withExternal()
.source("F2S").target("F2E")
.event("E_F2SE")
.and()
.withExternal()
.source("F3S").target("F3E")
.event("E_F3SE")
.and()
.withExternal()
.source("JN").target("END")
return builder.build()
}
}
And my controller looks like this:
@RestController
class StateMachineController {
@Autowired
private lateinit var stateMachine: StateMachine<String, String>
@Autowired
private lateinit var runtimePersister: StateMachineRuntimePersister<String, String, String>
@GetMapping("/state")
fun state(String, @RequestParam("event") event: String): String {
resetStateMachineFromStore()
feedStateMachine(event)
return stateMachine.state.toString()
}
private fun resetStateMachineFromStore() {
val context = runtimePersister.read("ItemSM")
if (context != null) {
stateMachine.stop()
stateMachine.stateMachineAccessor.doWithRegion {
it.resetStateMachine(context)
}
stateMachine.start()
}
}
private fun feedStateMachine(event: String) {
stateMachine.sendEvent(event)
}
}
If I trigger the events in the following order the following SQL statements are being executed:
'E_IS1' -> UPDATE STATE_MACHINE SET STATE='S1', [...] WHERE MACHINE_ID='ItemSM'
'E_FRK' -> UPDATE STATE_MACHINE SET STATE='GROUP', [...] WHERE MACHINE_ID='ItemSM'
-> UPDATE STATE_MACHINE SET STATE='F1I', [...] WHERE MACHINE_ID='ItemSM#R1'
-> UPDATE STATE_MACHINE SET STATE='F3I', [...] WHERE MACHINE_ID='ItemSM#R3'
-> UPDATE STATE_MACHINE SET STATE='F2I', [...] WHERE MACHINE_ID='ItemSM#R2'
'E_F1IS' -> UPDATE STATE_MACHINE SET STATE='F1S', [...] WHERE MACHINE_ID='ItemSM'
'E_F2IS' -> UPDATE STATE_MACHINE SET STATE='F2S', [...] WHERE MACHINE_ID='ItemSM'
For the last two events (E_F1IS/E_F2IS
) I would have expected the region rows ItemSM#R1
and ItemSM#R2
to get updated to F1S
and F2S
. Instead the main ItemSM
row gets updated twice.
This leads to the problem that the state machine cannot be restored properly. The resulting state machine is loaded with state GROUP
but the region states are all in the initial F1I,F2I,F3I
states.
Is there a problem with my state machine config or what is the reason for this behavior?
I have the exact same problem in version 3.0.1.
Any news about this?