This is a go implementation of erlang's gen_fsm
Erlang's gen_fsm
provides a nice way of implementing finite state machines, which can be described as:
State(S) x Event(E) -> Actions(A), State(S')
There are a couple of things nice about this:
- Event handlers for different states are just functions with states as function names, and event data as inputs.
- Each instance of fsm is run as a separate process providing concurrency.
-
Implement the init function to set initial state
func (f *MyFsm) Init(args... interface{}) State
-
Implement event handlers for all states. An event handler looks like this
func (f *MyFsm) State_Event(event_data) (State, Timeout)
whereState
is the next desired state, and timeout the amount of time intime.Duration
to wait to send a timeout event if nothing happens.
For eg. a door inLocked
state will transition toOpen
, when the right code is entered. This will look like this:
func (d *Door) Locked_Button(code rune) (go_gen_fsm.State,time.Duration){
if match(code){
return "Open", 5 * time.Second
}else{
return "Locked", -1
}
}
Here, the door will open
after the correct is entered, and a timeout event will be sent after 5 seconds. To handle the timeout event, we should define a handler for that. This will look like this:
func (d *Door) Open_Timeout() (go_gen_fsm.State){
return "Locked"
}
Now, the door will again be Locked
after the timeout.
- Create an instance of your fsm and start
go_gen_fsm
f := new(MyFsm)
g := go_gen_fsm.Start(f, args...)
where args
will be passed to the Init
method to initialize the fsm.
- Finally, To send an event, use the
SendEvent
api provided byGenFsm
(from the above step)
g.SendEvent(EventName, EventData...)
Internally, go_gen_fsm
starts a go routine when Start
is invoked. This acts as an event loop listening to events, and uses reflection to invoke the appropriate handlers, thereby providing concurrency.
A full implementation of a door state machine described here is implemented in the sample
package.