qmuntal / stateless

Go library for creating finite state machines
BSD 2-Clause "Simplified" License
942 stars 49 forks source link

Model vs Machine #2

Closed jwenz723 closed 4 years ago

jwenz723 commented 4 years ago

This is a question, not an issue. I am trying to gather the intended method of usage for this package.

I am wondering if there is a way with this package to define the valid triggers/states one time (maybe in func main(). Then afterwards, create a single StateMachine instance per incoming HTTP request using the previously created configuration (triggers/states)?

I am hoping to use this package in a way where I would define the triggers/states on application start up then I would use a new StateMachine instance for each new incoming HTTP request because my app is stateless. So for each incoming request I would do the following:

  1. retrieve current state from an external durable storage
  2. create a new StateMachine with the current state and the pre-defined valid triggers/states
  3. fire triggers according to the particular HTTP endpoint
  4. store end state into external durable storage and return data to HTTP endpoint caller
qmuntal commented 4 years ago

Hi @jwenz723, there is no need to instantiate a new StateMachine on every HTTP query, just reusing the one you created in your func main() should cover your use case. Take into account that calls to the state storage are already thread-safe and that the FiringQueued mode enqueue trigger fires so only one trigger is executed concurrently.

jwenz723 commented 4 years ago

I understand that the state transition triggers can execute in a thread-safe way, so you would only need 1 StateMachine instance per unique entity. However, my my scenario there are multiple entities which each have their own state. For example....

In the README you create a single StateMachine instance like this:

phoneCall := stateless.NewStateMachine(stateOffHook)

From my understanding this StateMachine represents a single phone call. In my scenario, I would like to have many phone calls exist at the same time, and therefore, each one of these phone calls should have their own StateMachine instance (I assume), because each phone call should be able to transition between states independent of the state of other phone calls.

Hopefully this makes sense. Please let me know if there is a better way to achieve state management of multiple entities.

qmuntal commented 4 years ago

Oh, i get it now. What I would do is create a function that returns a configured state machine on its initial state, something similar to:

func NewPhoneCall() *StateMachine {
  phoneCall := stateless.NewStateMachine(stateOffHook)
  phoneCall.Configure(stateOffHook).Permit(triggerCallDialed, stateRinging)
  return phoneCall
}

This way you centralize the state machine configuration and you just call it whenever a new one is needed.

Does it work for you?

jwenz723 commented 4 years ago

That makes sense. Thank you.