Finite State Machine (FSM) Package for Go
A flexible and thread-safe finite state machine (FSM) implementation for Go. This library allows
you to define custom states and transitions, manage state changes, and subscribe to state updates
using channels.
Features
- Define custom states and allowed transitions
- Thread-safe state management
- Subscribe to state changes via channels
- Logging support using the standard library's
log/slog
Installation
go get github.com/robbyt/go-finiteState
Usage
A full example is available in example/main.go
.
Defining States and Transitions
Define your custom states and the allowed transitions between them. There are also some predefined
states available in allowedTransitions.go
.
import (
"github.com/robbyt/go-finiteState/fsm"
)
// Define custom states
const (
StatusOnline = "StatusOnline"
StatusOffline = "StatusOffline"
StatusUnknown = "StatusUnknown"
)
// Define allowed transitions
var allowedTransitions = fsm.TransitionsConfig{
StatusOnline: string[]{StatusOffline, StatusUnknown},
StatusOffline: string[]{StatusOnline, StatusUnknown},
StatusUnknown: string[]{},
}
Creating a New FSM
Create a new FSM instance by providing an initial state and the allowed transitions. You can also
provide a logger using the standard library's log/slog.
import (
"github.com/robbyt/go-finiteState/fsm"
"log/slog"
)
func main() {
// Create a new logger
logger := slog.Default()
// Create a new FSM
machine, err := fsm.New(logger, StateIdle, allowedTransitions)
if err != nil {
logger.Error("Failed to create FSM", "error", err)
return
}
}
Transition between states using the Transition method. It ensures that the transition adheres to
the allowed transitions.
err = machine.Transition(StateRunning)
if err != nil {
logger.Error("Transition failed", "error", err)
}
Subscribing to State Changes
Subscribe to state changes by obtaining a channel that emits the FSM's state whenever it changes.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
stateChan := machine.GetStateChan(ctx)
go func() {
for state := range stateChan {
logger.Info("State changed", "state", state)
}
}()
License
This project is licensed under the Apache License 2.0