FSM-Go is a lightweight, high-performance, stateless finite state machine implementation in Go, inspired by Alibaba's COLA state machine component.
- 🪶 Lightweight - Minimal, stateless design for high performance
- 🔒 Type-safe - Built with Go generics for compile-time type checking
- 🔄 Fluent API - Intuitive builder pattern for defining state machines
- 🔀 Versatile Transitions - Support for external, internal, and parallel transitions
- 🧪 Conditional Logic - Flexible conditions to control when transitions occur
- 🎬 Action Execution - Custom actions that execute during transitions
- 🔄 Thread-safe - Designed for concurrent use in multi-threaded environments
- 📊 Visualization - Built-in support for generating state machine diagrams
go get github.com/lingcoder/fsm-go
package main
import (
"fmt"
"log"
"github.com/lingcoder/fsm-go"
)
// Define states
type OrderState string
const (
OrderCreated OrderState = "CREATED"
OrderPaid OrderState = "PAID"
OrderShipped OrderState = "SHIPPED"
OrderDelivered OrderState = "DELIVERED"
OrderCancelled OrderState = "CANCELLED"
)
// Define events
type OrderEvent string
const (
EventPay OrderEvent = "PAY"
EventShip OrderEvent = "SHIP"
EventDeliver OrderEvent = "DELIVER"
EventCancel OrderEvent = "CANCEL"
)
// Define payload
type OrderPayload struct {
OrderID string
Amount float64
}
func main() {
// Create a builder
builder := fsm.NewStateMachineBuilder[OrderState, OrderEvent, OrderPayload]()
// Define the state machine
builder.ExternalTransition().
From(OrderCreated).
To(OrderPaid).
On(EventPay).
WhenFunc(func(payload OrderPayload) bool {
// Check if amount is valid
return payload.Amount > 0
}).
PerformFunc(func(from, to OrderState, event OrderEvent, payload OrderPayload) error {
fmt.Printf("Order %s transitioning from %s to %s on event %s\n",
payload.OrderID, from, to, event)
return nil
})
builder.ExternalTransition().
From(OrderPaid).
To(OrderShipped).
On(EventShip).
WhenFunc(func(payload OrderPayload) bool {
return true
}).
PerformFunc(func(from, to OrderState, event OrderEvent, payload OrderPayload) error {
fmt.Printf("Order %s is being shipped\n", payload.OrderID)
return nil
})
// Define multiple source transitions
builder.ExternalTransitions().
FromAmong(OrderCreated, OrderPaid, OrderShipped).
To(OrderCancelled).
On(EventCancel).
WhenFunc(func(payload OrderPayload) bool {
return true
}).
PerformFunc(func(from, to OrderState, event OrderEvent, payload OrderPayload) error {
fmt.Printf("Order %s cancelled from %s state\n", payload.OrderID, from)
return nil
})
// Build the state machine
stateMachine, err := builder.Build("OrderStateMachine")
if err != nil {
log.Fatalf("Failed to build state machine: %v", err)
}
// Create payload
payload := OrderPayload{
OrderID: "ORD-20250425-001",
Amount: 100.0,
}
// Transition from CREATED to PAID
newState, err := stateMachine.FireEvent(OrderCreated, EventPay, payload)
if err != nil {
log.Fatalf("Transition failed: %v", err)
}
fmt.Printf("New state: %v\n", newState)
}
Concept | Description |
---|---|
State | Represents a specific state in your business process |
Event | Triggers state transitions |
Transition | Defines how states change in response to events |
Condition | Logic that determines if a transition should occur |
Action | Logic executed when a transition occurs |
StateMachine | The core component that manages states and transitions |
- External Transition: Transition between different states
- Internal Transition: Actions within the same state
- Parallel Transition: Transition to multiple states simultaneously
Check the examples
directory for more detailed examples:
examples/order
: Order processing workflowexamples/workflow
: Approval workflowexamples/game
: Game state management
FSM-Go is designed for high performance:
- Stateless design minimizes memory usage
- Efficient transition lookup
- Thread-safe for concurrent use
- Benchmarks included in the test suite
FSM-Go provides a unified way to visualize your state machine with different formats:
// Default format (PlantUML)
plantUML := stateMachine.GenerateDiagram()
fmt.Println(plantUML)
// Generate specific format
table := stateMachine.GenerateDiagram(fsm.MarkdownTable) // Markdown table format
fmt.Println(table)
flow := stateMachine.GenerateDiagram(fsm.MarkdownFlowchart) // Markdown flowchart format
fmt.Println(flow)
// Generate multiple formats separately
diagrams := stateMachine.GenerateDiagram(fsm.PlantUML, fsm.MarkdownTable, fsm.MarkdownFlowchart, fsm.MarkdownStateDiagram)
fmt.Println(diagrams)
MIT © LingCoder