spring-statemachine icon indicating copy to clipboard operation
spring-statemachine copied to clipboard

State Machine doesn't get restored using the stateMachineContext

Open zassyne opened this issue 7 years ago • 10 comments

I followed the datapersist sample, using Redis to persist a state machine. The issue is that, when I acquire a state machine that has been persisted before, the state machine gets created with a new context, This happens when I restart application (the java app), otherwise it restores the state machine correctly as it is using the map in DefaultStateMachineService: Map<String, StateMachine<S, E>> machines = new HashMap<String, StateMachine<S, E>>()

I have debugged the DefaultStateMachineService's public StateMachine<S, E> acquireStateMachine(String machineId, boolean start) method:

...
if (stateMachinePersist != null) {
	try {
		StateMachineContext<S, E> stateMachineContext = stateMachinePersist.read(machineId);
		stateMachine = restoreStateMachine(stateMachine, tateMachineContext);
	} catch (Exception e) {
		log.error("Error handling context", e);
		throw new StateMachineException("Unable to read context from store", e);
	}
}
...

So, stateMachinePersist.read(machineId) reads the context from Redis using the machineId, there is no problem with that as I debugged and the context is read correctly, BUT the restoreStateMachine(stateMachine, tateMachineContext) does NOT use that context, and as result I get a new state machine with a new context.

zassyne avatar Jan 18 '19 13:01 zassyne

Um, I don't quite follow. What do you mean it does not use that context?

jvalkeal avatar Jan 19 '19 14:01 jvalkeal

I tried this by:

$ docker run --name test-redis -d -p 6379:6379 redis
$ java -jar spring-statemachine-samples/datapersist/build/libs/spring-statemachine-samples-datapersist-2.1.0.BUILD-SNAPSHOT.jar --spring.profiles.active=redis

If I put those machines to different states and then restart sample, machines are restored.

jvalkeal avatar Jan 19 '19 15:01 jvalkeal

I mean that the new state machine that I am getting comes with a new context, current state, the extended state variables all the stuff is lost.. The AbstractStateMachine' resetStateMachine() method doesn't make use of the context, I debugged and as I found that it relies on the boolean stateSet flag which is not set to true.. and as result the following block doesn't get executed : if (stateSet && stateMachineContext.getExtendedState() != null) { this.extendedState.getVariables().clear(); this.extendedState.getVariables().putAll(stateMachineContext.getExtendedState().getVariables()); }

I am basing my code/config on the datatpersist sample, in my case, I add variables to the extended state of the machine, in the actions and guards, well all is working. except when I do a restart. the next time it restores the state machine, the variables are not there.. because of that stateSet flag in the AbstractStateMachine's resetStateMachine method which is always false in my case.

zassyne avatar Jan 19 '19 17:01 zassyne

If that flag is false then it feels like a bug. Can you roughly show a structure of your machine as that might show where things go wrong. I'm also starting to question myself what I actually did in that point in code where extended state is reset.

jvalkeal avatar Jan 20 '19 09:01 jvalkeal

I debugged the AbstractStateMachine's resetStateMachine method, I found the reason why the flag is never set to true, inside the iterations over states, the following condition is always false:

state instanceof Enum && ss.getId() instanceof Enum && state.getClass() == ss.getId().getClass() && ((Enum) ss.getId()).ordinal() == ((Enum) state).ordinal()

Because of state.getClass() == ss.getId().getClass() is never true, as the class loaders are different, due to the fact that I have spring-devtools in my dependencies which make use of a different classloader. It wasn't easy to find out why the restore is not working, I think it would be great to do some logging and tell the developer about that...

zassyne avatar Jan 22 '19 15:01 zassyne

Ah devtools, plot thickens. Not a first time it's causing issues. Maybe we could change that comparison to not use == as it's kinda stupid way to do it.

jvalkeal avatar Jan 22 '19 17:01 jvalkeal

Yes that's true.. anyway Thank you! So I solved the issue by excluding the spring-devtools dependency, but I came across few issues like having a state machine with (s1, s2), it was stored and the current state of the machine is s1, the machine is configured in such a way that there is a transition from s1 to s2 without any event, this transition doesn't take place after restoring the machine, and as a result the machine is broken and stuck in the state s1, another issue is restoring the machine and the current state has an Action, the action will not take place as well... any advises/ideas/possible workarounds to solve the both issues I will be very grateful!

zassyne avatar Jan 22 '19 18:01 zassyne

I need to create a test for that as reset stops/starts a machine and start should fire up execution which in theory should pick that anonymous transition.

jvalkeal avatar Jan 23 '19 08:01 jvalkeal

I debugged the AbstractStateMachine's resetStateMachine method, I found the reason why the flag is never set to true, inside the iterations over states, the following condition is always false:

state instanceof Enum && ss.getId() instanceof Enum && state.getClass() == ss.getId().getClass() && ((Enum) ss.getId()).ordinal() == ((Enum) state).ordinal()

Because of state.getClass() == ss.getId().getClass() is never true, as the class loaders are different, due to the fact that I have spring-devtools in my dependencies which make use of a different classloader. It wasn't easy to find out why the restore is not working, I think it would be great to do some logging and tell the developer about that...

Thank you! I had the same fucking issue here!

Removing devtools the StateMachine works fine.

FabianoLothor avatar Jan 17 '20 20:01 FabianoLothor

hey everyone! We have faced the same problem and this is really crap. it is defenitely should be issue for spring

xanddol avatar Feb 02 '22 17:02 xanddol