Bug: Delays are not properly restored when machine created from snapshot
XState version
XState version 5
Description
When using delays (after: { 1000: "myTarget" }), if the state machine is persisted during a delay and then restored by re-creating it from the snapshot, then the delay will never trigger.
Seems like the delay information is lost when snapshotting.
I've worked around it by using a fromPromise actor with a promise resolving after a setTimeout. The input of that actor is a deadline computed when it is created (Date.now() + delay in ms).
Expected result
The delay should be resumed and possibly trigger its resolution condition if it is past the expected time it should've completed.
Actual result
The delay never resolves and the state machine is stuck forever.
Reproduction
I didn't prepare any, but should be easy?
Additional context
No response
This hasn't been implemented yet; it's a bit tricky because there's no one-size-fits-all solution. There's (at least?) 3 possible ways it can resume:
- Resume from start time: end at the previous end time, as if the delay was still active
- Resume from remaining time: as if time "froze"
- Restart delay
Yes, that's true!
I was thinking making it configurable with a good default (principle of least surprise) would be ideal. Each would store different information to prevent getting stuck on snapshot restore (could be start time, end time, some boolean or something else).
The problem with this is that persistence's caveats aren't really documented. Is it not a feature that's used very much? For a while restoring was completely broken if a machine had children actors. I can only assume other such bugs are lurking.
Yeah, restoring from a snapshot is also tricky. A better solution I'd like to promote is event sourcing, since that would lead to a more accurate restoration of state.