Giter Club home page Giter Club logo

fsm's Introduction

Finite State Machine for Go

Overview

The FSM (Finite State Machine) is best described in the Erlang design principles

A FSM can be described as a set of relations of the form:

State(S) x Event(E) -> Actions (A), State(S')

These relations are interpreted as meaning:

If we are in state S and the event E occurs, we should perform the actions A and make a transition to the state S'.

A Simple Example

The code is taken from the article Akka Finite State Machine (FSM) and At Most Once Semantics

import (
	"fmt"
	"github.com/dyrkin/fsm"
)

//states
const InitialState = "Initial"
const AwaitFromState = "AwaitFrom"
const AwaitToState = "AwaitTo"
const DoneState = "Done"

//messages
type Transfer struct {
	source chan int
	target chan int
	amount int
}

const Done = "Done"
const Failed = "Failed"

//data
type WireTransferData struct {
	source chan int
	target chan int
	amount int
	client *fsm.FSM
}

func newWireTransfer(transferred chan bool) *fsm.FSM {
	wt := fsm.NewFSM()

	wt.StartWith(InitialState, nil)

	wt.When(InitialState)(
		func(event *fsm.Event) *fsm.NextState {
			transfer, transferOk := event.Message.(*Transfer)
			if transferOk && event.Data == nil {
				transfer.source <- transfer.amount
				return wt.Goto(AwaitFromState).With(
					&WireTransferData{transfer.source, transfer.target, transfer.amount, wt},
				)
			}
			return wt.DefaultHandler()(event)
		})

	wt.When(AwaitFromState)(
		func(event *fsm.Event) *fsm.NextState {
			data, dataOk := event.Data.(*WireTransferData)
			if dataOk {
				switch event.Message {
				case Done:
					data.target <- data.amount
					return wt.Goto(AwaitToState)
				case Failed:
					go data.client.Send(Failed)
					return wt.Stay()
				}
			}
			return wt.DefaultHandler()(event)
		})

	wt.When(AwaitToState)(
		func(event *fsm.Event) *fsm.NextState {
			data, dataOk := event.Data.(*WireTransferData)
			if dataOk {
				switch event.Message {
				case Done:
					transferred <- true
					return wt.Stay()
				case Failed:
					go data.client.Stay()
				}
			}
			return wt.DefaultHandler()(event)
		})
	return wt
}

The basic strategy is to instantiate FSM and specifying the possible states:

  • NewFSM() instantiates new FSM
  • StartWith() defines the initial state and initial data
  • Then there is one When(<state>)(<event handler fn>) declaration per state to be handled.

In this case will start in the Initial state with all values uninitialized. The only type of message which can be received in the Initial state is the initial Transfer request at which point a withdraw amount is sent to the source account and the state machine transitions to the AwaitFrom state.

When the system is in the AwaitFrom state the only two messages that can be received are Done or Failure from the source account. If the Done business acknowledgement is received the system will send a deposit amount to the target account and transition to the AwaitTo state.

When the system is in the AwaitTo state the only two messages that can be received are the Done or Failure from the target account.

To run the code above you can use the following code:

func main() {

	transferred := make(chan bool)

	wireTransfer := newWireTransfer(transferred)

	transfer := &Transfer{
		source: make(chan int),
		target: make(chan int),
		amount: 30,
	}

	source := func() {
		withdrawAmount := <-transfer.source
		fmt.Printf("Withdrawn from source account: %d\n", withdrawAmount)
		wireTransfer.Send(Done)
	}

	target := func() {
		topupAmount := <-transfer.target
		fmt.Printf("ToppedUp target account: %d\n", topupAmount)
		wireTransfer.Send(Done)
	}

	go source()
	go target()

	go wireTransfer.Send(transfer)

	if done := <-transferred; !done {
		panic("Something went wrong")
	}

	fmt.Println("DONE")
}

It will produce the following output:

Withdrawn from source account: 30
ToppedUp target account: 30
DONE

fsm's People

Contributors

dyrkin avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.