xstate: Persisting Parallel State Machines Fails
Description I’m trying to repeatedly externally step a parallel state machine with persistence. I have set up a simple linear machine that goes a -> b -> c -> d and notes entry and exit.
The base machine is
states: {
a: {
entry: ["doEntry"],
exit: ["doExit"],
on: { TRIGGER: { target: "b" } }
},
b: {
entry: ["doEntry"],
exit: ["doExit"],
on: { TRIGGER: { target: "c" } }
},
c: {
entry: ["doEntry"],
exit: ["doExit"],
on: { TRIGGER: { target: "d" } }
},
d: { type: "final" }
}
In the code sandbox I set up 4 tests.
I create a parallel machine which uses two instance of the base machine.
- Simple Linear works as expected.
- Simple Parallel also works as expected. You see two entrys to a, two exits of a… etc
- Step Linear Works, but complains about Warning: No implementation found for action type I would like to know why that is the case, but the output looks correct
- Step Parallel does not work.
For quick reference, the serialize/deserialize code is snipped below:
function step(machine, jsonState) {
const service = interpret(machine);
if (jsonState === null) {
service.start();
} else {
var restoredState = State.create(JSON.parse(jsonState));
service.start(restoredState);
service.send("TRIGGER");
}
var retVal = JSON.stringify(service.state);
service.stop();
return retVal;
}
function parallelStepTest (machine) {
console.log('start')
jsonState.b = step(machine, null)
console.log('step 1')
jsonState.c = step(machine, jsonState.b)
console.log('step 2')
jsonState.d = step(machine, jsonState.c)
}
Expected Result
Step Parallel
start
entry a
entry a
step 1
exit a
exit a
entry b
entry b
step 2
exit b
exit b
entry c
entry c
step 3
exit c
exit c
Actual Result
Step Parallel
start
entry a
entry a
step 1
entry a
entry a
exit a
entry b
exit a
entry b
step 2
step 3
Reproduction
Additional context
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 2
- Comments: 19 (7 by maintainers)
@davidkpiano I/We appreciate it. XState is impressive work. I would think wanting to persist complex states (and store them in a database) is a probably pretty common use case. Maybe if the documentation added an example of the "right way"™ to take a complex machine and persist/rehydrate, it would go a long way.
As an example, the one at the bottom of https://xstate.js.org/docs/guides/parallel.html has hierarchy and parallel machines
Either way, thanks for creating XState. It’s impressive work.
I appreciate it, thank you! Persisting complex states should “just work” ideally.
Has anyone successfully achieved this? I’m having a lot of trouble restoring child states correctly.
I created a new version of the code sandbox which captures the issue I’m having here: https://codesandbox.io/s/xstate-parallel-machine-persist-ktjtw
It appears to correctly restore the state for step 1… however on step 2 and further it hits
console.log('no service for ' + name)because the call toservice.start(resolvedState)does not create the service.children map.If anyone has a simple example of recursive machine re-hydration, or a suggestion as to why service.start isn’t creating the children I’d greatly appreciate it.
Thanks.
Hello @Andarist, thanks for following up.
Yes, I would expect to be able to serialize the complex machine at any state and then resume it at a later point.
Thanks for the tip there. I didn’t realize that capturing the state of a machine wouldn’t include the child states. I would expect it would do so. Is there a case where you might want to save a parent state without capturing the child states?
Either way, I will investigate recursively descending into child properties to save/restore state. If you or anyone else has an example of this, I would appreciate it very much.
Thanks again!