ifandelse / machina.js

js ex machina - finite state machines in JavaScript
http://machina-js.org/
Other
1.93k stars 147 forks source link

How to persist state and create FSM from persisted state? #140

Closed atwj closed 6 years ago

atwj commented 7 years ago

Hey! I saw a brief mention of it in the wiki, any idea how this would work?

If its not a feature yet I was thinking it could be something like:

// saving state
var state = somefsm.getState();
db.store(state)

//restoring state
var fsm = machina.Fsm.parse(db.get('state'))
sescobb27 commented 7 years ago

We are using the BehavioralFSM which has a __machina__ property, having that in mind we add that attribute to our mongodb schema then we persist our models to the DB, giving us the persistence we need, then we can find our models and pass them to our FSMs to manage them. this may help you (FSM extends BFSM here https://github.com/ifandelse/machina.js/blob/master/src/Fsm.js#L84. now the problem we are having is that we need to customize the MACHINA_PROP (__machina__) which is a global variable, we would like it to be customizable via the options param, not overriding a global variable which can cause other problems (we are using multiple BFSMs) https://github.com/ifandelse/machina.js/blob/master/src/BehavioralFsm.js#L7

const subscriptionSchema = new Schema({
  subscriptionId: { type: String },
  plan: { type: String, },
  __machina__: {
    type: {},
    default: {}
  }
})
salmansaifi7 commented 7 years ago

@atwj were you able to solve this problem? I also need quite similar kind of thing. I have hundreds of states in my app, so looking for modularizing these states in separate files (each having related states).

ifandelse commented 6 years ago

@atwj So sorry for the long delay in replying. I intentionally didn't bake any storage-specific behavior into machina because the options are nearly endless, and it wasn't a core focus of the library. You could absolutely attach your own getState method to any FSM, which gives you the control you need to only grab and serialize the relevant state - you'd just also need to provide a way to feed that stored state back into an FSM if the intent is to retrieve from storage and continue working the FSM where you left off. @sescobb27 mentioned the BehavioralFsm - this is how I would typically go about handling state that I need to persist and then retrieve later and feed back to the FSM. However, I want to be clear that the __machina___ property is not a global variable (it's a prop attached to the client state object, not set on your runtime's global). BehavioralFsms are only behavior - any state you need to keep track of is passed as part of the client argument (first arg to any method on the BehavioralFsm). That client state object is assigned a __machina__ property so that the FSM can store metadata about the state that client is in, etc. As long as your client state object is serializable, you should be able to store it, retrieve it and feed it back to an FSM without any issue (see #123 for a simple example of persisting state to a json file and retrieving, etc.).

@sescobb27 FWIW, I hadn't run into a situation where the same client objects were being fed to multiple BehavioralFsms - I'll look into allowing that property to be more configurable in the next major version bump. Thanks!