Documentation
¶
Overview ¶
Package statekit provides a Go-native statechart execution engine.
Define and execute statecharts in Go — visualize them with built-in tools.
Features ¶
- Fluent Builder API
- Hierarchical States (Compound/Nested)
- History States (Shallow and Deep)
- Delayed Transitions (Timers)
- Parallel States (Orthogonal Regions)
- Reflection DSL (Struct tags)
- Native Visualization (HTML simulator, Mermaid, ASCII, TUI)
Quick Start ¶
machine, _ := statekit.NewMachine[struct{}]("traffic").
WithInitial("green").
State("green").On("TIMER").Target("yellow").Done().
State("yellow").On("TIMER").Target("red").Done().
State("red").On("TIMER").Target("green").Done().
Build()
interp := statekit.NewInterpreter(machine)
interp.Start()
interp.Send(statekit.Event{Type: "TIMER"})
Visualization ¶
Export your machine to Statekit Native JSON for visualization:
exporter := export.NewNativeExporter(machine)
jsonStr, _ := exporter.ExportJSONIndent("", " ")
fmt.Println(jsonStr)
Or use the CLI:
statekit viz --go-package . --format html -o machine.html
Package statekit provides event sourcing support for state machine persistence.
Example ¶
package main
import (
"fmt"
"github.com/felixgeelhaar/statekit"
)
func main() {
// Create a simple traffic light state machine
machine, _ := statekit.NewMachine[struct{}]("traffic").
WithInitial("green").
State("green").On("TIMER").Target("yellow").Done().
State("yellow").On("TIMER").Target("red").Done().
State("red").On("TIMER").Target("green").Done().
Build()
interp := statekit.NewInterpreter(machine)
interp.Start()
fmt.Println(interp.State().Value)
interp.Send(statekit.Event{Type: "TIMER"})
fmt.Println(interp.State().Value)
}
Output: green yellow
Index ¶
- Constants
- Variables
- func FromStruct[M any, C any](registry *ActionRegistry[C]) (*ir.MachineConfig[C], error)
- func FromStructWithContext[M any, C any](registry *ActionRegistry[C], ctx C) (*ir.MachineConfig[C], error)
- type Action
- type ActionRegistry
- type ActionType
- type ActorID
- type ActorMetadata
- type ActorRef
- type ClusterMembership
- type ClusterNode
- type CompoundNode
- type ConsistentHashRouter
- type DistributedInterpreter
- func (di *DistributedInterpreter[C]) Commit(ctx context.Context) (int, error)
- func (di *DistributedInterpreter[C]) Context() C
- func (di *DistributedInterpreter[C]) Done() bool
- func (di *DistributedInterpreter[C]) ForceSnapshot(ctx context.Context) error
- func (di *DistributedInterpreter[C]) LockHeld() bool
- func (di *DistributedInterpreter[C]) LockLost() <-chan struct{}
- func (di *DistributedInterpreter[C]) Matches(stateID StateID) bool
- func (di *DistributedInterpreter[C]) Send(event Event) error
- func (di *DistributedInterpreter[C]) SendAll(events []Event) error
- func (di *DistributedInterpreter[C]) State() State[C]
- func (di *DistributedInterpreter[C]) Stop(ctx context.Context) error
- func (di *DistributedInterpreter[C]) StreamID() string
- func (di *DistributedInterpreter[C]) UncommittedCount() int
- func (di *DistributedInterpreter[C]) Version() int
- type DistributedInterpreterOption
- type ErrConcurrencyConflict
- type Event
- type EventStore
- type EventType
- type FinalNode
- type Guard
- type GuardType
- type HistoryBuilder
- type HistoryType
- type Interpreter
- func NewInterpreter[C any](machine *ir.MachineConfig[C]) *Interpreter[C]
- func ReplayEvents[C any](ctx context.Context, machine *ir.MachineConfig[C], eventStore EventStore, ...) (*Interpreter[C], error)
- func ReplayToVersion[C any](ctx context.Context, machine *ir.MachineConfig[C], eventStore EventStore, ...) (*Interpreter[C], error)
- func (i *Interpreter[C]) Done() bool
- func (i *Interpreter[C]) GetActor(id ActorID) *ActorRef
- func (i *Interpreter[C]) Matches(id StateID) bool
- func (i *Interpreter[C]) Restore(s Snapshot[C]) error
- func (i *Interpreter[C]) Send(event Event)
- func (i *Interpreter[C]) SendParent(event Event) error
- func (i *Interpreter[C]) SendTo(id ActorID, event Event) error
- func (i *Interpreter[C]) Snapshot() Snapshot[C]
- func (i *Interpreter[C]) Start()
- func (i *Interpreter[C]) State() State[C]
- func (i *Interpreter[C]) Stop()
- func (i *Interpreter[C]) UpdateContext(fn func(ctx *C))
- func (i *Interpreter[C]) Use(p plugin.Plugin[C])
- type InvokeBuilder
- func (b *InvokeBuilder[C]) Done() *MachineBuilder[C]
- func (b *InvokeBuilder[C]) End() *StateBuilder[C]
- func (b *InvokeBuilder[C]) ID(id string) *InvokeBuilder[C]
- func (b *InvokeBuilder[C]) OnDone(target StateID) *InvokeBuilder[C]
- func (b *InvokeBuilder[C]) OnDoneAction(action ActionType) *InvokeBuilder[C]
- func (b *InvokeBuilder[C]) OnError(target StateID) *InvokeBuilder[C]
- func (b *InvokeBuilder[C]) OnErrorAction(action ActionType) *InvokeBuilder[C]
- type Lock
- type MachineBuilder
- func (b *MachineBuilder[C]) Build() (*ir.MachineConfig[C], error)
- func (b *MachineBuilder[C]) State(id StateID) *StateBuilder[C]
- func (b *MachineBuilder[C]) WithAction(name ActionType, action Action[C]) *MachineBuilder[C]
- func (b *MachineBuilder[C]) WithChildMachine(name string, factory ir.ChildMachineFactory[C]) *MachineBuilder[C]
- func (b *MachineBuilder[C]) WithContext(ctx C) *MachineBuilder[C]
- func (b *MachineBuilder[C]) WithGuard(name GuardType, guard Guard[C]) *MachineBuilder[C]
- func (b *MachineBuilder[C]) WithInitial(initial StateID) *MachineBuilder[C]
- func (b *MachineBuilder[C]) WithService(name ServiceType, service Service[C]) *MachineBuilder[C]
- type MachineConfig
- type MachineDef
- type MachineInvokeBuilder
- func (b *MachineInvokeBuilder[C]) AutoForward(events ...EventType) *MachineInvokeBuilder[C]
- func (b *MachineInvokeBuilder[C]) Done() *MachineBuilder[C]
- func (b *MachineInvokeBuilder[C]) End() *StateBuilder[C]
- func (b *MachineInvokeBuilder[C]) ID(id string) *MachineInvokeBuilder[C]
- func (b *MachineInvokeBuilder[C]) OnDone(target StateID) *MachineInvokeBuilder[C]
- func (b *MachineInvokeBuilder[C]) OnDoneAction(action ActionType) *MachineInvokeBuilder[C]
- func (b *MachineInvokeBuilder[C]) OnError(target StateID) *MachineInvokeBuilder[C]
- func (b *MachineInvokeBuilder[C]) OnErrorAction(action ActionType) *MachineInvokeBuilder[C]
- type MachineSnapshot
- type MembershipEvent
- type MembershipEventType
- type MemoryEventStore
- func (s *MemoryEventStore) AppendEvents(ctx context.Context, streamID string, expectedVersion int, ...) error
- func (s *MemoryEventStore) GetStreamVersion(ctx context.Context, streamID string) (int, error)
- func (s *MemoryEventStore) LoadEvents(ctx context.Context, streamID string, fromVersion int) ([]PersistedEvent, error)
- type MemorySnapshotStore
- type MemoryStreamLock
- type PendingTimer
- type PersistedEvent
- type PersistentInterpreter
- func (pi *PersistentInterpreter[C]) Commit(ctx context.Context) (int, error)
- func (pi *PersistentInterpreter[C]) Context() C
- func (pi *PersistentInterpreter[C]) Done() bool
- func (pi *PersistentInterpreter[C]) ForceSnapshot(ctx context.Context) error
- func (pi *PersistentInterpreter[C]) Matches(stateID StateID) bool
- func (pi *PersistentInterpreter[C]) Rollback()
- func (pi *PersistentInterpreter[C]) Send(event Event)
- func (pi *PersistentInterpreter[C]) SendAll(events []Event)
- func (pi *PersistentInterpreter[C]) State() State[C]
- func (pi *PersistentInterpreter[C]) Stop()
- func (pi *PersistentInterpreter[C]) StreamID() string
- func (pi *PersistentInterpreter[C]) UncommittedCount() int
- func (pi *PersistentInterpreter[C]) Version() int
- type PersistentInterpreterOption
- type RegionBuilder
- type RestoreError
- type Service
- type ServiceContext
- type ServiceType
- type Snapshot
- type SnapshotConfig
- type SnapshotStore
- type SnapshotStrategy
- type SpawnOption
- type State
- type StateBuilder
- func (b *StateBuilder[C]) After(d time.Duration) *TransitionBuilder[C]
- func (b *StateBuilder[C]) Done() *MachineBuilder[C]
- func (b *StateBuilder[C]) End() *StateBuilder[C]
- func (b *StateBuilder[C]) EndState() *RegionBuilder[C]
- func (b *StateBuilder[C]) Final() *StateBuilder[C]
- func (b *StateBuilder[C]) History(id StateID) *HistoryBuilder[C]
- func (b *StateBuilder[C]) Invoke(src ServiceType) *InvokeBuilder[C]
- func (b *StateBuilder[C]) InvokeMachine(machineRef string) *MachineInvokeBuilder[C]
- func (b *StateBuilder[C]) On(event EventType) *TransitionBuilder[C]
- func (b *StateBuilder[C]) OnEntry(action ActionType) *StateBuilder[C]
- func (b *StateBuilder[C]) OnExit(action ActionType) *StateBuilder[C]
- func (b *StateBuilder[C]) Parallel() *StateBuilder[C]
- func (b *StateBuilder[C]) Region(id StateID) *RegionBuilder[C]
- func (b *StateBuilder[C]) State(id StateID) *StateBuilder[C]
- func (b *StateBuilder[C]) WithInitial(initial StateID) *StateBuilder[C]
- type StateID
- type StateNode
- type StateType
- type StreamLock
- type StreamRouter
- type SupervisionStrategy
- type TransitionBuilder
- func (b *TransitionBuilder[C]) After(d time.Duration) *TransitionBuilder[C]
- func (b *TransitionBuilder[C]) Do(action ActionType) *TransitionBuilder[C]
- func (b *TransitionBuilder[C]) Done() *MachineBuilder[C]
- func (b *TransitionBuilder[C]) End() *StateBuilder[C]
- func (b *TransitionBuilder[C]) EndState() *RegionBuilder[C]
- func (b *TransitionBuilder[C]) Guard(guard GuardType) *TransitionBuilder[C]
- func (b *TransitionBuilder[C]) On(event EventType) *TransitionBuilder[C]
- func (b *TransitionBuilder[C]) Target(target StateID) *TransitionBuilder[C]
Examples ¶
Constants ¶
const ( ErrCodeSnapshotMachineMismatch = "SNAPSHOT_MACHINE_MISMATCH" ErrCodeSnapshotInvalidState = "SNAPSHOT_INVALID_STATE" ErrCodeSnapshotVersionMismatch = "SNAPSHOT_VERSION_MISMATCH" )
Error codes for snapshot operations
const ( StateTypeAtomic = ir.StateTypeAtomic StateTypeCompound = ir.StateTypeCompound StateTypeFinal = ir.StateTypeFinal StateTypeHistory = ir.StateTypeHistory // v2.0 StateTypeParallel = ir.StateTypeParallel // v2.0 HistoryTypeShallow = ir.HistoryTypeShallow // v2.0 HistoryTypeDeep = ir.HistoryTypeDeep // v2.0 )
Re-export constants
Variables ¶
var ErrActorAlreadyExists = errors.New("actor already exists")
ErrActorAlreadyExists is returned when spawning an actor with a duplicate ID
var ErrActorNotFound = errors.New("actor not found")
ErrActorNotFound is returned when an actor ID doesn't exist in the registry
var ErrActorStopped = errors.New("actor stopped")
ErrActorStopped is returned when sending to a stopped actor
var ErrLockHeld = errors.New("lock held by another node")
ErrLockHeld is returned when attempting to acquire a lock held by another node.
var ErrLockLost = errors.New("lock lost")
ErrLockLost is returned when a lock is lost unexpectedly.
var ErrNoParent = errors.New("no parent actor")
ErrNoParent is returned when SendParent is called on a root interpreter
Functions ¶
func FromStruct ¶
func FromStruct[M any, C any](registry *ActionRegistry[C]) (*ir.MachineConfig[C], error)
FromStruct builds a MachineConfig from a struct definition using the reflection DSL.
The struct M must embed MachineDef and define states using StateNode, CompoundNode, or FinalNode marker types with appropriate struct tags.
Actions and guards referenced in tags must be registered in the provided ActionRegistry.
Example:
type MyMachine struct {
statekit.MachineDef `id:"example" initial:"idle"`
Idle statekit.StateNode `on:"START->running:canStart" entry:"logStart"`
Running statekit.StateNode `on:"STOP->idle"`
}
registry := statekit.NewActionRegistry[MyContext]().
WithAction("logStart", func(ctx *MyContext, e statekit.Event) { ... }).
WithGuard("canStart", func(ctx MyContext, e statekit.Event) bool { ... })
machine, err := statekit.FromStruct[MyMachine, MyContext](registry)
func FromStructWithContext ¶
func FromStructWithContext[M any, C any](registry *ActionRegistry[C], ctx C) (*ir.MachineConfig[C], error)
FromStructWithContext builds a MachineConfig with an initial context value.
Types ¶
type Action ¶
Action is a side-effect function executed during transitions. It receives a pointer to the context for modification and the triggering event.
type ActionRegistry ¶
type ActionRegistry[C any] struct { // contains filtered or unexported fields }
ActionRegistry holds action and guard function implementations that are referenced by name in the reflection DSL.
ActionRegistry is not safe for concurrent use. It should be fully configured before calling FromStruct or FromStructWithContext.
func NewActionRegistry ¶
func NewActionRegistry[C any]() *ActionRegistry[C]
NewActionRegistry creates a new empty action registry.
func (*ActionRegistry[C]) WithAction ¶
func (r *ActionRegistry[C]) WithAction(name ActionType, action Action[C]) *ActionRegistry[C]
WithAction registers an action function by name. Returns the registry for method chaining.
func (*ActionRegistry[C]) WithGuard ¶
func (r *ActionRegistry[C]) WithGuard(name GuardType, guard Guard[C]) *ActionRegistry[C]
WithGuard registers a guard function by name. Returns the registry for method chaining.
type ActorID ¶ added in v0.8.0
type ActorID string
ActorID uniquely identifies a spawned child actor
type ActorMetadata ¶ added in v0.14.0
type ActorMetadata struct {
// ID is the actor's unique identifier
ID ActorID `json:"id"`
// SpawnedInState is the state that spawned this actor
SpawnedInState StateID `json:"spawned_in_state"`
// Supervision is the supervision strategy for this actor
Supervision SupervisionStrategy `json:"supervision"`
// AutoForward lists event types that were auto-forwarded to this actor
AutoForward []EventType `json:"auto_forward,omitempty"`
}
ActorMetadata captures information about a spawned actor for persistence (v0.14). This is a metadata-only snapshot - the actor's internal state is not captured. When restoring, actors must be manually respawned by the application.
type ActorRef ¶ added in v0.8.0
type ActorRef struct {
// contains filtered or unexported fields
}
ActorRef provides a handle to communicate with a spawned child actor. It is safe to use concurrently from multiple goroutines.
func Spawn ¶ added in v0.8.0
func Spawn[ParentC, ChildC any]( parent *Interpreter[ParentC], id ActorID, childMachine *ir.MachineConfig[ChildC], opts ...SpawnOption, ) (*ActorRef, error)
Spawn creates and starts a child actor from a machine configuration. The actor is associated with the current state and will be stopped when that state is exited (state-scoped lifecycle).
Options can configure supervision strategy, auto-forwarding, and completion handlers.
func SpawnWithContext ¶ added in v0.8.0
func SpawnWithContext[ParentC, ChildC any]( parent *Interpreter[ParentC], id ActorID, childMachine *ir.MachineConfig[ChildC], initContext func(ParentC) ChildC, opts ...SpawnOption, ) (*ActorRef, error)
SpawnWithContext is like Spawn but allows initializing the child context from the parent context.
func (*ActorRef) Done ¶ added in v0.8.0
func (a *ActorRef) Done() <-chan struct{}
Done returns a channel that's closed when the actor stops. Use this to wait for actor completion.
type ClusterMembership ¶ added in v0.8.0
type ClusterMembership interface {
// Join registers this node with the cluster.
Join(ctx context.Context, node ClusterNode) error
// Leave removes this node from the cluster.
Leave(ctx context.Context) error
// Members returns all known cluster members.
Members(ctx context.Context) ([]ClusterNode, error)
// Watch returns a channel that receives membership changes.
Watch(ctx context.Context) (<-chan MembershipEvent, error)
}
ClusterMembership provides cluster membership management. Implementations can use etcd, consul, or a custom gossip protocol.
type ClusterNode ¶ added in v0.8.0
type ClusterNode struct {
ID string
Address string
JoinedAt time.Time
LastSeen time.Time
Metadata map[string]string
}
ClusterNode represents a node in the cluster.
type CompoundNode ¶
type CompoundNode struct{}
CompoundNode is a marker type for defining compound (nested) states.
Use struct tags to configure the compound state:
- initial:"childState" - Required initial child state
- on:"EVENT->target" - Parent-level transitions
- entry:"action" - Parent entry actions
- exit:"action" - Parent exit actions
Child states are defined as fields within the struct that embeds CompoundNode.
Example:
type ActiveState struct {
statekit.CompoundNode `initial:"idle" on:"RESET->done"`
Idle statekit.StateNode `on:"START->working"`
Working statekit.StateNode `on:"STOP->idle"`
}
type ConsistentHashRouter ¶ added in v0.8.0
type ConsistentHashRouter struct {
// Replicas is the number of virtual nodes per physical node.
Replicas int
}
ConsistentHashRouter routes streams using consistent hashing.
func NewConsistentHashRouter ¶ added in v0.8.0
func NewConsistentHashRouter(replicas int) *ConsistentHashRouter
NewConsistentHashRouter creates a new consistent hash router.
func (*ConsistentHashRouter) IsLocal ¶ added in v0.8.0
func (r *ConsistentHashRouter) IsLocal(streamID string, members []ClusterNode, localNodeID string) bool
IsLocal returns true if this node should handle the stream.
func (*ConsistentHashRouter) RouteStream ¶ added in v0.8.0
func (r *ConsistentHashRouter) RouteStream(streamID string, members []ClusterNode) string
RouteStream returns the node that should handle the stream using consistent hashing.
type DistributedInterpreter ¶ added in v0.8.0
type DistributedInterpreter[C any] struct { // contains filtered or unexported fields }
DistributedInterpreter wraps a PersistentInterpreter with distributed locking. It ensures only one node processes events for a stream at a time.
func NewDistributedInterpreter ¶ added in v0.8.0
func NewDistributedInterpreter[C any]( ctx context.Context, streamID string, machine *ir.MachineConfig[C], eventStore EventStore, streamLock StreamLock, opts ...DistributedInterpreterOption[C], ) (*DistributedInterpreter[C], error)
NewDistributedInterpreter creates a new distributed interpreter. It acquires a lock for the stream before hydrating state.
func (*DistributedInterpreter[C]) Commit ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) Commit(ctx context.Context) (int, error)
Commit persists uncommitted events.
func (*DistributedInterpreter[C]) Context ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) Context() C
Context returns the current context.
func (*DistributedInterpreter[C]) Done ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) Done() bool
Done returns true if in a final state.
func (*DistributedInterpreter[C]) ForceSnapshot ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) ForceSnapshot(ctx context.Context) error
ForceSnapshot creates a snapshot.
func (*DistributedInterpreter[C]) LockHeld ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) LockHeld() bool
LockHeld returns true if the lock is still held.
func (*DistributedInterpreter[C]) LockLost ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) LockLost() <-chan struct{}
LockLost returns a channel that's closed when the lock is lost.
func (*DistributedInterpreter[C]) Matches ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) Matches(stateID StateID) bool
Matches checks if current state matches or is descendant of given state.
func (*DistributedInterpreter[C]) Send ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) Send(event Event) error
Send processes an event if the lock is still held.
func (*DistributedInterpreter[C]) SendAll ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) SendAll(events []Event) error
SendAll processes multiple events.
func (*DistributedInterpreter[C]) State ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) State() State[C]
State returns the current state.
func (*DistributedInterpreter[C]) Stop ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) Stop(ctx context.Context) error
Stop releases the lock and stops the interpreter.
func (*DistributedInterpreter[C]) StreamID ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) StreamID() string
StreamID returns the stream identifier.
func (*DistributedInterpreter[C]) UncommittedCount ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) UncommittedCount() int
UncommittedCount returns the number of uncommitted events.
func (*DistributedInterpreter[C]) Version ¶ added in v0.8.0
func (di *DistributedInterpreter[C]) Version() int
Version returns the current stream version.
type DistributedInterpreterOption ¶ added in v0.8.0
type DistributedInterpreterOption[C any] func(*DistributedInterpreter[C])
DistributedInterpreterOption configures a DistributedInterpreter.
func WithDistributedSnapshotConfig ¶ added in v0.8.0
func WithDistributedSnapshotConfig[C any](config SnapshotConfig) DistributedInterpreterOption[C]
WithDistributedSnapshotConfig sets the snapshot configuration.
func WithDistributedSnapshotStore ¶ added in v0.8.0
func WithDistributedSnapshotStore[C any](store SnapshotStore[C]) DistributedInterpreterOption[C]
WithDistributedSnapshotStore sets the snapshot store.
func WithLockTTL ¶ added in v0.8.0
func WithLockTTL[C any](ttl time.Duration) DistributedInterpreterOption[C]
WithLockTTL sets the lock TTL and renewal interval. Defaults: TTL=30s, renewInterval=10s (renew at 1/3 of TTL).
type ErrConcurrencyConflict ¶ added in v0.8.0
ErrConcurrencyConflict is returned when optimistic concurrency check fails.
func (*ErrConcurrencyConflict) Error ¶ added in v0.8.0
func (e *ErrConcurrencyConflict) Error() string
type EventStore ¶ added in v0.8.0
type EventStore interface {
// AppendEvents atomically appends events to a stream.
// Returns ErrConcurrencyConflict if expectedVersion doesn't match.
AppendEvents(ctx context.Context, streamID string, expectedVersion int, events []PersistedEvent) error
// LoadEvents loads all events for a stream from a specific version.
// Pass fromVersion=0 to load all events.
LoadEvents(ctx context.Context, streamID string, fromVersion int) ([]PersistedEvent, error)
// GetStreamVersion returns the current version of a stream.
// Returns 0 if the stream doesn't exist.
GetStreamVersion(ctx context.Context, streamID string) (int, error)
}
EventStore defines the interface for event persistence. Implementations handle storage of events for event sourcing.
type FinalNode ¶
type FinalNode struct{}
FinalNode is a marker type for defining final states.
Final states indicate the machine has completed. They typically have no outgoing transitions.
Example:
Completed statekit.FinalNode
type Guard ¶
Guard is a predicate that determines if a transition should occur. It receives the current context (by value) and the triggering event.
type HistoryBuilder ¶ added in v0.4.0
type HistoryBuilder[C any] struct { // contains filtered or unexported fields }
HistoryBuilder provides a fluent API for constructing history states
func (*HistoryBuilder[C]) Deep ¶ added in v0.4.0
func (b *HistoryBuilder[C]) Deep() *HistoryBuilder[C]
Deep sets the history type to deep (remembers full leaf path)
func (*HistoryBuilder[C]) Default ¶ added in v0.4.0
func (b *HistoryBuilder[C]) Default(target StateID) *HistoryBuilder[C]
Default sets the default target state if no history is recorded
func (*HistoryBuilder[C]) End ¶ added in v0.4.0
func (b *HistoryBuilder[C]) End() *StateBuilder[C]
End completes the history state definition and returns to the parent StateBuilder
func (*HistoryBuilder[C]) Shallow ¶ added in v0.4.0
func (b *HistoryBuilder[C]) Shallow() *HistoryBuilder[C]
Shallow sets the history type to shallow (remembers immediate child)
type HistoryType ¶ added in v0.4.0
type HistoryType = ir.HistoryType
HistoryType specifies how history states remember previous states (v2.0)
type Interpreter ¶
type Interpreter[C any] struct { // contains filtered or unexported fields }
Interpreter is the statechart runtime that processes events and manages state
func NewInterpreter ¶
func NewInterpreter[C any](machine *ir.MachineConfig[C]) *Interpreter[C]
NewInterpreter creates a new interpreter for the given machine configuration
func ReplayEvents ¶ added in v0.8.0
func ReplayEvents[C any]( ctx context.Context, machine *ir.MachineConfig[C], eventStore EventStore, streamID string, ) (*Interpreter[C], error)
ReplayEvents replays events from the store to a new interpreter. Useful for debugging or creating a read model.
func ReplayToVersion ¶ added in v0.8.0
func ReplayToVersion[C any]( ctx context.Context, machine *ir.MachineConfig[C], eventStore EventStore, streamID string, targetVersion int, ) (*Interpreter[C], error)
ReplayToVersion replays events up to a specific version.
func (*Interpreter[C]) Done ¶
func (i *Interpreter[C]) Done() bool
Done returns true if the machine is in a final state
func (*Interpreter[C]) GetActor ¶ added in v0.8.0
func (i *Interpreter[C]) GetActor(id ActorID) *ActorRef
GetActor returns the ActorRef for the given ID, or nil if not found
func (*Interpreter[C]) Matches ¶
func (i *Interpreter[C]) Matches(id StateID) bool
Matches checks if the current state matches the given state ID For hierarchical states, returns true if current state equals id or is a descendant of id For parallel states, also checks all active region states
Example ¶
package main
import (
"fmt"
"github.com/felixgeelhaar/statekit"
)
func main() {
machine, _ := statekit.NewMachine[struct{}]("nested").
WithInitial("parent").
State("parent").
WithInitial("child").
State("child").End().
Done().
Build()
interp := statekit.NewInterpreter(machine)
interp.Start()
// Current state is "child"
fmt.Println(interp.State().Value)
// Matches both the current state and its ancestors
fmt.Println(interp.Matches("child"))
fmt.Println(interp.Matches("parent"))
}
Output: child true true
func (*Interpreter[C]) Restore ¶ added in v0.5.0
func (i *Interpreter[C]) Restore(s Snapshot[C]) error
Restore restores the interpreter to the state captured in the snapshot. The machine configuration must match (same machine ID). Returns an error if the snapshot is incompatible.
func (*Interpreter[C]) Send ¶
func (i *Interpreter[C]) Send(event Event)
Send processes an event and potentially transitions to a new state
func (*Interpreter[C]) SendParent ¶ added in v0.8.0
func (i *Interpreter[C]) SendParent(event Event) error
SendParent sends an event to the parent interpreter. Returns ErrNoParent if this is a root interpreter (no parent).
func (*Interpreter[C]) SendTo ¶ added in v0.8.0
func (i *Interpreter[C]) SendTo(id ActorID, event Event) error
SendTo sends an event to a specific child actor by ID
func (*Interpreter[C]) Snapshot ¶ added in v0.5.0
func (i *Interpreter[C]) Snapshot() Snapshot[C]
Snapshot creates a snapshot of the current interpreter state. The snapshot captures all information needed to restore the interpreter to this exact state later.
Note on actors: Actor metadata is captured but actors are NOT automatically restored. The SpawnedActors field contains metadata about what actors were running, allowing the application to manually respawn them if needed.
func (*Interpreter[C]) Start ¶
func (i *Interpreter[C]) Start()
Start initializes the interpreter and enters the initial state
func (*Interpreter[C]) State ¶
func (i *Interpreter[C]) State() State[C]
State returns the current state of the interpreter
func (*Interpreter[C]) Stop ¶ added in v0.4.0
func (i *Interpreter[C]) Stop()
Stop cancels all active timers, services, invoked machines, and actors, then stops the interpreter
func (*Interpreter[C]) UpdateContext ¶
func (i *Interpreter[C]) UpdateContext(fn func(ctx *C))
UpdateContext allows updating the context with a function
func (*Interpreter[C]) Use ¶ added in v0.14.0
func (i *Interpreter[C]) Use(p plugin.Plugin[C])
Use registers a plugin with the interpreter. Plugins receive callbacks during interpreter execution. Multiple plugins can be registered; they are called in registration order.
type InvokeBuilder ¶ added in v0.5.0
type InvokeBuilder[C any] struct { // contains filtered or unexported fields }
InvokeBuilder provides a fluent API for constructing service invocations (v3.0)
func (*InvokeBuilder[C]) Done ¶ added in v0.5.0
func (b *InvokeBuilder[C]) Done() *MachineBuilder[C]
Done completes the state definition and returns to the machine builder
func (*InvokeBuilder[C]) End ¶ added in v0.5.0
func (b *InvokeBuilder[C]) End() *StateBuilder[C]
End completes the invocation definition and returns to the StateBuilder
func (*InvokeBuilder[C]) ID ¶ added in v0.5.0
func (b *InvokeBuilder[C]) ID(id string) *InvokeBuilder[C]
ID sets a custom ID for this invocation
func (*InvokeBuilder[C]) OnDone ¶ added in v0.5.0
func (b *InvokeBuilder[C]) OnDone(target StateID) *InvokeBuilder[C]
OnDone sets the transition target when the service completes successfully
func (*InvokeBuilder[C]) OnDoneAction ¶ added in v0.5.0
func (b *InvokeBuilder[C]) OnDoneAction(action ActionType) *InvokeBuilder[C]
OnDoneAction sets an action to execute when the service completes successfully
func (*InvokeBuilder[C]) OnError ¶ added in v0.5.0
func (b *InvokeBuilder[C]) OnError(target StateID) *InvokeBuilder[C]
OnError sets the transition target when the service fails
func (*InvokeBuilder[C]) OnErrorAction ¶ added in v0.5.0
func (b *InvokeBuilder[C]) OnErrorAction(action ActionType) *InvokeBuilder[C]
OnErrorAction sets an action to execute when the service fails
type Lock ¶ added in v0.8.0
type Lock interface {
// Renew extends the lock's TTL.
Renew(ctx context.Context, ttl time.Duration) error
// Release releases the lock.
Release(ctx context.Context) error
// Done returns a channel that's closed when the lock is lost.
Done() <-chan struct{}
}
Lock represents a held distributed lock.
type MachineBuilder ¶
type MachineBuilder[C any] struct { // contains filtered or unexported fields }
MachineBuilder provides a fluent API for constructing state machines
func NewMachine ¶
func NewMachine[C any](id string) *MachineBuilder[C]
NewMachine creates a new MachineBuilder with the given ID
Example (Hierarchical) ¶
package main
import (
"fmt"
"github.com/felixgeelhaar/statekit"
)
func main() {
// Hierarchical state machine with nested states
machine, _ := statekit.NewMachine[struct{}]("editor").
WithInitial("editing").
State("editing").
WithInitial("idle").
On("SAVE").Target("saved").End(). // Parent handles SAVE for all children
State("idle").
On("TYPE").Target("dirty").
End().
End().
State("dirty").
On("CLEAR").Target("idle").
End().
End().
Done().
State("saved").Final().Done().
Build()
interp := statekit.NewInterpreter(machine)
interp.Start()
fmt.Println(interp.State().Value) // Starts in leaf state
fmt.Println(interp.Matches("editing")) // Matches parent
interp.Send(statekit.Event{Type: "TYPE"})
fmt.Println(interp.State().Value)
interp.Send(statekit.Event{Type: "SAVE"}) // Bubbles up to parent
fmt.Println(interp.State().Value)
}
Output: idle true dirty saved
Example (WithAction) ¶
package main
import (
"fmt"
"github.com/felixgeelhaar/statekit"
)
func main() {
type Context struct {
Count int
}
machine, _ := statekit.NewMachine[Context]("counter").
WithInitial("idle").
WithAction("increment", func(ctx *Context, e statekit.Event) {
ctx.Count++
}).
State("idle").
OnEntry("increment").
On("COUNT").Target("idle").
Done().
Build()
interp := statekit.NewInterpreter(machine)
interp.Start()
fmt.Println(interp.State().Context.Count) // Entry action runs on Start
interp.Send(statekit.Event{Type: "COUNT"})
fmt.Println(interp.State().Context.Count) // Entry action runs again on self-transition
}
Output: 1 2
Example (WithGuard) ¶
package main
import (
"fmt"
"github.com/felixgeelhaar/statekit"
)
func main() {
type Context struct {
Approved bool
}
machine, _ := statekit.NewMachine[Context]("approval").
WithInitial("pending").
WithContext(Context{Approved: true}).
WithGuard("isApproved", func(ctx Context, e statekit.Event) bool {
return ctx.Approved
}).
State("pending").
On("SUBMIT").Target("approved").Guard("isApproved").
Done().
State("approved").Final().Done().
Build()
interp := statekit.NewInterpreter(machine)
interp.Start()
interp.Send(statekit.Event{Type: "SUBMIT"})
fmt.Println(interp.State().Value)
}
Output: approved
func (*MachineBuilder[C]) Build ¶
func (b *MachineBuilder[C]) Build() (*ir.MachineConfig[C], error)
Build constructs the final MachineConfig from the builder
func (*MachineBuilder[C]) State ¶
func (b *MachineBuilder[C]) State(id StateID) *StateBuilder[C]
State starts building a new state with the given ID
func (*MachineBuilder[C]) WithAction ¶
func (b *MachineBuilder[C]) WithAction(name ActionType, action Action[C]) *MachineBuilder[C]
WithAction registers a named action
func (*MachineBuilder[C]) WithChildMachine ¶ added in v0.14.0
func (b *MachineBuilder[C]) WithChildMachine(name string, factory ir.ChildMachineFactory[C]) *MachineBuilder[C]
WithChildMachine registers a child machine factory for machine composition (v0.14). The factory creates a child interpreter when the machine is invoked.
func (*MachineBuilder[C]) WithContext ¶
func (b *MachineBuilder[C]) WithContext(ctx C) *MachineBuilder[C]
WithContext sets the initial context value
func (*MachineBuilder[C]) WithGuard ¶
func (b *MachineBuilder[C]) WithGuard(name GuardType, guard Guard[C]) *MachineBuilder[C]
WithGuard registers a named guard
func (*MachineBuilder[C]) WithInitial ¶
func (b *MachineBuilder[C]) WithInitial(initial StateID) *MachineBuilder[C]
WithInitial sets the initial state ID
func (*MachineBuilder[C]) WithService ¶ added in v0.5.0
func (b *MachineBuilder[C]) WithService(name ServiceType, service Service[C]) *MachineBuilder[C]
WithService registers a named service (v3.0)
type MachineConfig ¶
type MachineConfig[C any] = ir.MachineConfig[C]
MachineConfig is the immutable internal representation of a statechart
type MachineDef ¶
type MachineDef struct{}
MachineDef is a marker type that must be embedded in a struct to define a state machine using the reflection DSL.
Use struct tags to configure the machine:
- id:"machineId" - Required machine identifier
- initial:"stateName" - Required initial state name
Example:
type MyMachine struct {
statekit.MachineDef `id:"myMachine" initial:"idle"`
Idle statekit.StateNode `on:"START->running"`
Running statekit.StateNode `on:"STOP->idle"`
}
type MachineInvokeBuilder ¶ added in v0.14.0
type MachineInvokeBuilder[C any] struct { // contains filtered or unexported fields }
MachineInvokeBuilder provides a fluent API for constructing child machine invocations (v0.14)
func (*MachineInvokeBuilder[C]) AutoForward ¶ added in v0.14.0
func (b *MachineInvokeBuilder[C]) AutoForward(events ...EventType) *MachineInvokeBuilder[C]
AutoForward adds event types that should be auto-forwarded to the child machine
func (*MachineInvokeBuilder[C]) Done ¶ added in v0.14.0
func (b *MachineInvokeBuilder[C]) Done() *MachineBuilder[C]
Done completes the state definition and returns to the machine builder
func (*MachineInvokeBuilder[C]) End ¶ added in v0.14.0
func (b *MachineInvokeBuilder[C]) End() *StateBuilder[C]
End completes the machine invocation definition and returns to the StateBuilder
func (*MachineInvokeBuilder[C]) ID ¶ added in v0.14.0
func (b *MachineInvokeBuilder[C]) ID(id string) *MachineInvokeBuilder[C]
ID sets a custom ID for this machine invocation
func (*MachineInvokeBuilder[C]) OnDone ¶ added in v0.14.0
func (b *MachineInvokeBuilder[C]) OnDone(target StateID) *MachineInvokeBuilder[C]
OnDone sets the transition target when the child machine reaches a final state
func (*MachineInvokeBuilder[C]) OnDoneAction ¶ added in v0.14.0
func (b *MachineInvokeBuilder[C]) OnDoneAction(action ActionType) *MachineInvokeBuilder[C]
OnDoneAction sets an action to execute when the child machine completes
func (*MachineInvokeBuilder[C]) OnError ¶ added in v0.14.0
func (b *MachineInvokeBuilder[C]) OnError(target StateID) *MachineInvokeBuilder[C]
OnError sets the transition target when the child machine encounters an error
func (*MachineInvokeBuilder[C]) OnErrorAction ¶ added in v0.14.0
func (b *MachineInvokeBuilder[C]) OnErrorAction(action ActionType) *MachineInvokeBuilder[C]
OnErrorAction sets an action to execute when the child machine fails
type MachineSnapshot ¶ added in v0.8.0
type MachineSnapshot[C any] struct { // Current state value StateValue ir.StateID `json:"state_value"` // Full state path for hierarchical states StatePath []ir.StateID `json:"state_path,omitempty"` // Machine context Context C `json:"context"` // History memory for shallow history states HistoryShallow map[ir.StateID]ir.StateID `json:"history_shallow,omitempty"` // History memory for deep history states HistoryDeep map[ir.StateID]ir.StateID `json:"history_deep,omitempty"` // Parallel region states ActiveInParallel map[ir.StateID]ir.StateID `json:"active_in_parallel,omitempty"` // Current parallel state (if any) CurrentParallel ir.StateID `json:"current_parallel,omitempty"` // Timestamp when snapshot was taken Timestamp time.Time `json:"timestamp"` }
MachineSnapshot captures the complete state of an interpreter for persistence.
type MembershipEvent ¶ added in v0.8.0
type MembershipEvent struct {
Type MembershipEventType
Node ClusterNode
}
MembershipEvent represents a cluster membership change.
type MembershipEventType ¶ added in v0.8.0
type MembershipEventType int
MembershipEventType indicates the type of membership change.
const ( // MemberJoined indicates a new member joined. MemberJoined MembershipEventType = iota // MemberLeft indicates a member left gracefully. MemberLeft // MemberFailed indicates a member failed (no heartbeat). MemberFailed )
type MemoryEventStore ¶ added in v0.8.0
type MemoryEventStore struct {
// contains filtered or unexported fields
}
MemoryEventStore is an in-memory implementation of EventStore for testing.
func NewMemoryEventStore ¶ added in v0.8.0
func NewMemoryEventStore() *MemoryEventStore
NewMemoryEventStore creates a new in-memory event store.
func (*MemoryEventStore) AppendEvents ¶ added in v0.8.0
func (s *MemoryEventStore) AppendEvents(ctx context.Context, streamID string, expectedVersion int, events []PersistedEvent) error
AppendEvents atomically appends events to a stream.
func (*MemoryEventStore) GetStreamVersion ¶ added in v0.8.0
GetStreamVersion returns the current version of a stream.
func (*MemoryEventStore) LoadEvents ¶ added in v0.8.0
func (s *MemoryEventStore) LoadEvents(ctx context.Context, streamID string, fromVersion int) ([]PersistedEvent, error)
LoadEvents loads all events for a stream from a specific version.
type MemorySnapshotStore ¶ added in v0.8.0
type MemorySnapshotStore[C any] struct { // contains filtered or unexported fields }
MemorySnapshotStore is an in-memory implementation of SnapshotStore for testing.
func NewMemorySnapshotStore ¶ added in v0.8.0
func NewMemorySnapshotStore[C any]() *MemorySnapshotStore[C]
NewMemorySnapshotStore creates a new in-memory snapshot store.
func (*MemorySnapshotStore[C]) LoadSnapshot ¶ added in v0.8.0
func (s *MemorySnapshotStore[C]) LoadSnapshot(ctx context.Context, streamID string, maxVersion int) (*MachineSnapshot[C], int, error)
LoadSnapshot loads the latest snapshot at or before maxVersion.
func (*MemorySnapshotStore[C]) SaveSnapshot ¶ added in v0.8.0
func (s *MemorySnapshotStore[C]) SaveSnapshot(ctx context.Context, streamID string, version int, snapshot *MachineSnapshot[C]) error
SaveSnapshot saves a state snapshot at the given version.
type MemoryStreamLock ¶ added in v0.8.0
type MemoryStreamLock struct {
// contains filtered or unexported fields
}
MemoryStreamLock is an in-memory implementation of StreamLock for testing. In production, use Redis, etcd, or PostgreSQL advisory locks.
func NewMemoryStreamLock ¶ added in v0.8.0
func NewMemoryStreamLock() *MemoryStreamLock
NewMemoryStreamLock creates a new in-memory stream lock.
func (*MemoryStreamLock) Acquire ¶ added in v0.8.0
func (s *MemoryStreamLock) Acquire(ctx context.Context, streamID string, ttl time.Duration) (Lock, error)
Acquire blocks until the lock is acquired or context is cancelled.
func (*MemoryStreamLock) TryAcquire ¶ added in v0.8.0
func (s *MemoryStreamLock) TryAcquire(ctx context.Context, streamID string, ttl time.Duration) (Lock, error)
TryAcquire attempts to acquire a lock without blocking.
type PendingTimer ¶ added in v0.5.0
type PendingTimer struct {
// StateID is the state that owns this delayed transition
StateID StateID `json:"state_id"`
// TransitionIndex identifies which transition in the state
TransitionIndex int `json:"transition_index"`
// Target is the destination state
Target StateID `json:"target"`
// Remaining is how much time is left until the timer fires
Remaining time.Duration `json:"remaining_ns"`
}
PendingTimer represents an active delayed transition that hasn't fired yet.
type PersistedEvent ¶ added in v0.8.0
type PersistedEvent struct {
// ID is a unique identifier for this event (e.g., UUID)
ID string `json:"id"`
// StreamID identifies the aggregate/stream this event belongs to
StreamID string `json:"stream_id"`
// Type is the event type that triggered the transition
Type EventType `json:"type"`
// Version is the stream version (monotonically increasing per stream)
Version int `json:"version"`
// Timestamp when the event was recorded
Timestamp time.Time `json:"timestamp"`
// Payload contains serialized event data
Payload json.RawMessage `json:"payload,omitempty"`
// Metadata holds additional context (correlation ID, user ID, etc.)
Metadata map[string]any `json:"metadata,omitempty"`
// StateAfter is the state after processing this event
StateAfter ir.StateID `json:"state_after"`
}
PersistedEvent represents a stored event in the event store.
type PersistentInterpreter ¶ added in v0.8.0
type PersistentInterpreter[C any] struct { // contains filtered or unexported fields }
PersistentInterpreter wraps an Interpreter with event sourcing capabilities. All state transitions are persisted to an EventStore and can be replayed.
func NewPersistentInterpreter ¶ added in v0.8.0
func NewPersistentInterpreter[C any]( ctx context.Context, streamID string, machine *ir.MachineConfig[C], eventStore EventStore, opts ...PersistentInterpreterOption[C], ) (*PersistentInterpreter[C], error)
NewPersistentInterpreter creates a new persistent interpreter. It automatically hydrates state from the event store if events exist.
func (*PersistentInterpreter[C]) Commit ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) Commit(ctx context.Context) (int, error)
Commit persists all uncommitted events to the event store. Returns the number of events committed.
func (*PersistentInterpreter[C]) Context ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) Context() C
Context returns a copy of the current context.
func (*PersistentInterpreter[C]) Done ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) Done() bool
Done returns true if the interpreter is in a final state.
func (*PersistentInterpreter[C]) ForceSnapshot ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) ForceSnapshot(ctx context.Context) error
ForceSnapshot creates a snapshot regardless of the configured strategy.
func (*PersistentInterpreter[C]) Matches ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) Matches(stateID StateID) bool
Matches checks if the current state matches or is a descendant of the given state.
func (*PersistentInterpreter[C]) Rollback ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) Rollback()
Rollback discards all uncommitted events.
func (*PersistentInterpreter[C]) Send ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) Send(event Event)
Send processes an event and records it for persistence. Events are recorded if they match a transition (including self-transitions). Events that don't match any transition are not recorded. Call Commit() to persist uncommitted events.
func (*PersistentInterpreter[C]) SendAll ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) SendAll(events []Event)
SendAll processes multiple events.
func (*PersistentInterpreter[C]) State ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) State() State[C]
State returns the current state.
func (*PersistentInterpreter[C]) Stop ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) Stop()
Stop stops the underlying interpreter.
func (*PersistentInterpreter[C]) StreamID ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) StreamID() string
StreamID returns the stream identifier.
func (*PersistentInterpreter[C]) UncommittedCount ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) UncommittedCount() int
UncommittedCount returns the number of uncommitted events.
func (*PersistentInterpreter[C]) Version ¶ added in v0.8.0
func (pi *PersistentInterpreter[C]) Version() int
Version returns the current stream version.
type PersistentInterpreterOption ¶ added in v0.8.0
type PersistentInterpreterOption[C any] func(*PersistentInterpreter[C])
PersistentInterpreterOption configures a PersistentInterpreter.
func WithSnapshotConfig ¶ added in v0.8.0
func WithSnapshotConfig[C any](config SnapshotConfig) PersistentInterpreterOption[C]
WithSnapshotConfig sets the snapshot configuration.
func WithSnapshotStore ¶ added in v0.8.0
func WithSnapshotStore[C any](store SnapshotStore[C]) PersistentInterpreterOption[C]
WithSnapshotStore sets the snapshot store for the interpreter.
type RegionBuilder ¶ added in v0.4.0
type RegionBuilder[C any] struct { // contains filtered or unexported fields }
RegionBuilder provides a fluent API for constructing parallel regions (v2.0)
func (*RegionBuilder[C]) EndRegion ¶ added in v0.4.0
func (b *RegionBuilder[C]) EndRegion() *StateBuilder[C]
EndRegion completes the region and returns to the parent parallel state
func (*RegionBuilder[C]) State ¶ added in v0.4.0
func (b *RegionBuilder[C]) State(id StateID) *StateBuilder[C]
State starts building a state within this region
func (*RegionBuilder[C]) WithInitial ¶ added in v0.4.0
func (b *RegionBuilder[C]) WithInitial(initial StateID) *RegionBuilder[C]
WithInitial sets the initial state for this region
type RestoreError ¶ added in v0.5.0
RestoreError represents an error during snapshot restoration.
func (*RestoreError) Error ¶ added in v0.5.0
func (e *RestoreError) Error() string
type Service ¶ added in v0.5.0
Service is an async operation invoked when entering a state. It runs in a goroutine and can send events back to the machine. The service should respect the context for cancellation.
type ServiceContext ¶ added in v0.5.0
type ServiceContext[C any] = ir.ServiceContext[C]
ServiceContext provides the execution context for a service (v3.0)
type ServiceType ¶ added in v0.5.0
type ServiceType = ir.ServiceType
ServiceType identifies a named service (v3.0)
type Snapshot ¶ added in v0.5.0
type Snapshot[C any] struct { // MachineID identifies which machine type this snapshot belongs to MachineID string `json:"machine_id"` // Version is the machine version for compatibility checking Version string `json:"version,omitempty"` // CurrentState is the active state ID (leaf state, or parallel state ID) CurrentState StateID `json:"current_state"` // Context is the user-defined context data Context C `json:"context"` // ShallowHistory maps compound state IDs to their last active child ShallowHistory map[StateID]StateID `json:"shallow_history,omitempty"` // DeepHistory maps compound state IDs to their last active leaf DeepHistory map[StateID]StateID `json:"deep_history,omitempty"` // ActiveInParallel maps region IDs to their current leaf states // Only populated when snapshot was taken from a parallel state ActiveInParallel map[StateID]StateID `json:"active_in_parallel,omitempty"` // CurrentParallel holds the parallel state ID if currently in a parallel state CurrentParallel StateID `json:"current_parallel,omitempty"` // PendingTimers captures active delayed transitions PendingTimers []PendingTimer `json:"pending_timers,omitempty"` // SpawnedActors captures metadata about spawned child actors (v0.14) // Note: Actors are NOT automatically restored. This metadata allows // the application to manually respawn actors if needed. SpawnedActors []ActorMetadata `json:"spawned_actors,omitempty"` // CreatedAt is when the snapshot was taken CreatedAt time.Time `json:"created_at"` }
Snapshot captures the complete state of an interpreter for persistence. It can be serialized to JSON and later used to restore an interpreter to the exact same state.
func (Snapshot[C]) MarshalJSON ¶ added in v0.5.0
MarshalJSON serializes the snapshot to JSON.
func (*Snapshot[C]) UnmarshalJSON ¶ added in v0.5.0
UnmarshalJSON deserializes the snapshot from JSON.
type SnapshotConfig ¶ added in v0.8.0
type SnapshotConfig struct {
// Strategy determines when to create snapshots
Strategy SnapshotStrategy
// Interval is the number of events between snapshots (for SnapshotByInterval)
Interval int
// TimeInterval is the duration between snapshots (for SnapshotByTime)
TimeInterval time.Duration
}
SnapshotConfig configures snapshot behavior.
type SnapshotStore ¶ added in v0.8.0
type SnapshotStore[C any] interface { // SaveSnapshot saves a state snapshot at the given version. SaveSnapshot(ctx context.Context, streamID string, version int, snapshot *MachineSnapshot[C]) error // LoadSnapshot loads the latest snapshot at or before maxVersion. // Returns nil if no snapshot exists. LoadSnapshot(ctx context.Context, streamID string, maxVersion int) (*MachineSnapshot[C], int, error) }
SnapshotStore defines the interface for state snapshot persistence. Snapshots enable faster state reconstruction by avoiding full event replay.
type SnapshotStrategy ¶ added in v0.8.0
type SnapshotStrategy int
SnapshotStrategy determines when snapshots are created.
const ( // SnapshotNever disables automatic snapshots SnapshotNever SnapshotStrategy = iota // SnapshotByInterval creates snapshots every N events SnapshotByInterval // SnapshotOnFinal creates a snapshot when reaching a final state SnapshotOnFinal // SnapshotByTime creates snapshots after a time interval SnapshotByTime )
type SpawnOption ¶ added in v0.8.0
type SpawnOption func(*spawnOptions)
SpawnOption configures actor spawning behavior
func WithAutoForward ¶ added in v0.8.0
func WithAutoForward(events ...EventType) SpawnOption
WithAutoForward configures events to automatically forward to the child
func WithOnDone ¶ added in v0.8.0
func WithOnDone(target StateID) SpawnOption
WithOnDone sets the target state when the child reaches a final state
func WithOnError ¶ added in v0.8.0
func WithOnError(target StateID) SpawnOption
WithOnError sets the target state when the child encounters an error
func WithSupervision ¶ added in v0.8.0
func WithSupervision(s SupervisionStrategy) SpawnOption
WithSupervision sets the supervision strategy for the spawned actor
type State ¶
type State[C any] struct { Value StateID // Current state ID (leaf state, or parallel state when in parallel) Context C // Current context // Parallel state tracking (v2.0) // When inside a parallel state, maps region ID to its current leaf state // Empty when not in a parallel state ActiveInParallel map[StateID]StateID }
State represents the current runtime state of an interpreter
type StateBuilder ¶
type StateBuilder[C any] struct { // contains filtered or unexported fields }
StateBuilder provides a fluent API for constructing states
func (*StateBuilder[C]) After ¶ added in v0.4.0
func (b *StateBuilder[C]) After(d time.Duration) *TransitionBuilder[C]
After starts building a delayed transition that triggers automatically after the specified duration (v2.0)
func (*StateBuilder[C]) Done ¶
func (b *StateBuilder[C]) Done() *MachineBuilder[C]
Done completes the state definition and returns to the parent builder For nested states, returns to the parent StateBuilder For root states, returns to the MachineBuilder
func (*StateBuilder[C]) End ¶
func (b *StateBuilder[C]) End() *StateBuilder[C]
End completes a nested state and returns to the parent StateBuilder Use this instead of Done() when building nested states
func (*StateBuilder[C]) EndState ¶ added in v0.4.0
func (b *StateBuilder[C]) EndState() *RegionBuilder[C]
EndState completes a state within a region and returns to the RegionBuilder (v2.0) Use this instead of End() when building states inside parallel regions
func (*StateBuilder[C]) Final ¶
func (b *StateBuilder[C]) Final() *StateBuilder[C]
Final marks this state as a final state
func (*StateBuilder[C]) History ¶ added in v0.4.0
func (b *StateBuilder[C]) History(id StateID) *HistoryBuilder[C]
History starts building a history state within this compound state (v2.0) History states remember the last active child and transition back to it
func (*StateBuilder[C]) Invoke ¶ added in v0.5.0
func (b *StateBuilder[C]) Invoke(src ServiceType) *InvokeBuilder[C]
Invoke starts building a service invocation for this state (v3.0) The service is started when entering the state and cancelled when exiting
func (*StateBuilder[C]) InvokeMachine ¶ added in v0.14.0
func (b *StateBuilder[C]) InvokeMachine(machineRef string) *MachineInvokeBuilder[C]
InvokeMachine starts building a child machine invocation for this state (v0.14). The child machine is spawned when entering the state and stopped when exiting. The machineRef must match a name registered with WithChildMachine.
func (*StateBuilder[C]) On ¶
func (b *StateBuilder[C]) On(event EventType) *TransitionBuilder[C]
On starts building a new transition triggered by the given event
func (*StateBuilder[C]) OnEntry ¶
func (b *StateBuilder[C]) OnEntry(action ActionType) *StateBuilder[C]
OnEntry adds an entry action to the state
func (*StateBuilder[C]) OnExit ¶
func (b *StateBuilder[C]) OnExit(action ActionType) *StateBuilder[C]
OnExit adds an exit action to the state
func (*StateBuilder[C]) Parallel ¶ added in v0.4.0
func (b *StateBuilder[C]) Parallel() *StateBuilder[C]
Parallel marks this state as a parallel state (v2.0) Use Region() to add orthogonal regions that execute simultaneously
func (*StateBuilder[C]) Region ¶ added in v0.4.0
func (b *StateBuilder[C]) Region(id StateID) *RegionBuilder[C]
Region starts building a new region within this parallel state (v2.0)
func (*StateBuilder[C]) State ¶
func (b *StateBuilder[C]) State(id StateID) *StateBuilder[C]
State starts building a nested child state
func (*StateBuilder[C]) WithInitial ¶
func (b *StateBuilder[C]) WithInitial(initial StateID) *StateBuilder[C]
WithInitial sets the initial child state for a compound state
type StateNode ¶
type StateNode struct{}
StateNode is a marker type for defining atomic states in the reflection DSL.
Use struct tags to configure the state:
- on:"EVENT->target" - Define a transition (can specify multiple with comma)
- on:"EVENT->target:guard" - Transition with guard condition
- on:"EVENT->target/action1;action2" - Transition with actions
- on:"EVENT->target/action:guard" - Transition with action and guard
- entry:"action1,action2" - Entry actions
- exit:"action1,action2" - Exit actions
Example:
Idle statekit.StateNode `on:"START->running:canStart" entry:"logIdle"`
type StreamLock ¶ added in v0.8.0
type StreamLock interface {
// Acquire attempts to acquire a lock for the given stream.
// Returns a Lock handle if successful, or an error if the lock is held by another node.
// The lock should automatically expire after ttl if not renewed.
Acquire(ctx context.Context, streamID string, ttl time.Duration) (Lock, error)
// TryAcquire attempts to acquire a lock without blocking.
// Returns ErrLockHeld if the lock is already held by another node.
TryAcquire(ctx context.Context, streamID string, ttl time.Duration) (Lock, error)
}
StreamLock provides distributed locking for state machine streams. Implementations can use Redis, etcd, PostgreSQL advisory locks, etc.
type StreamRouter ¶ added in v0.8.0
type StreamRouter interface {
// RouteStream returns the node ID that should handle the stream.
RouteStream(streamID string, members []ClusterNode) string
// IsLocal returns true if this node should handle the stream.
IsLocal(streamID string, members []ClusterNode, localNodeID string) bool
}
StreamRouter determines which node should handle a given stream. This enables consistent hashing for stream distribution.
type SupervisionStrategy ¶ added in v0.8.0
type SupervisionStrategy int
SupervisionStrategy defines how parent handles child actor errors
const ( // SupervisionEscalate bubbles the error to the parent via xstate.error.actor.<id> event SupervisionEscalate SupervisionStrategy = iota // SupervisionRecover logs the error and continues without stopping the child SupervisionRecover // SupervisionRestart stops the child and restarts it with initial state SupervisionRestart // SupervisionStop stops the child silently without generating an error event SupervisionStop )
type TransitionBuilder ¶
type TransitionBuilder[C any] struct { // contains filtered or unexported fields }
TransitionBuilder provides a fluent API for constructing transitions
func (*TransitionBuilder[C]) After ¶ added in v0.4.0
func (b *TransitionBuilder[C]) After(d time.Duration) *TransitionBuilder[C]
After starts a new delayed transition on the same state (chainable) (v2.0)
func (*TransitionBuilder[C]) Do ¶
func (b *TransitionBuilder[C]) Do(action ActionType) *TransitionBuilder[C]
Do adds an action to be executed during the transition
func (*TransitionBuilder[C]) Done ¶
func (b *TransitionBuilder[C]) Done() *MachineBuilder[C]
Done completes the state definition and returns to the machine builder
func (*TransitionBuilder[C]) End ¶
func (b *TransitionBuilder[C]) End() *StateBuilder[C]
End completes the transition and returns to the parent StateBuilder Use this instead of Done() when building transitions in nested states
func (*TransitionBuilder[C]) EndState ¶ added in v0.4.0
func (b *TransitionBuilder[C]) EndState() *RegionBuilder[C]
EndState completes the transition and returns to the RegionBuilder (v2.0) Use this when building transitions in states inside parallel regions
func (*TransitionBuilder[C]) Guard ¶
func (b *TransitionBuilder[C]) Guard(guard GuardType) *TransitionBuilder[C]
Guard sets the guard condition for the transition
func (*TransitionBuilder[C]) On ¶
func (b *TransitionBuilder[C]) On(event EventType) *TransitionBuilder[C]
On starts a new transition on the same state (chainable)
func (*TransitionBuilder[C]) Target ¶
func (b *TransitionBuilder[C]) Target(target StateID) *TransitionBuilder[C]
Target sets the target state for the transition
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
statekit
command
Package main provides the statekit CLI tool for visualizing state machines.
|
Package main provides the statekit CLI tool for visualizing state machines. |
|
statekit-mcp
command
|
|
|
statekit/commands
Package commands provides CLI commands for the statekit tool.
|
Package commands provides CLI commands for the statekit tool. |
|
Package debug provides utilities for debugging and inspecting statekit state machines.
|
Package debug provides utilities for debugging and inspecting statekit state machines. |
|
examples
|
|
|
actor_supervisor
command
Package main demonstrates the actor model features of statekit.
|
Package main demonstrates the actor model features of statekit. |
|
form_wizard
command
Package main demonstrates history states with a multi-step form wizard.
|
Package main demonstrates history states with a multi-step form wizard. |
|
game_save
command
Package main demonstrates persistence with snapshots for a game save system.
|
Package main demonstrates persistence with snapshots for a game save system. |
|
incident_lifecycle
command
Package main demonstrates an SRE incident lifecycle using hierarchical states.
|
Package main demonstrates an SRE incident lifecycle using hierarchical states. |
|
logging_plugin
command
Package main demonstrates the plugin system for extending interpreter behavior.
|
Package main demonstrates the plugin system for extending interpreter behavior. |
|
order_workflow
command
Package main demonstrates an e-commerce order workflow using the reflection DSL.
|
Package main demonstrates an e-commerce order workflow using the reflection DSL. |
|
pedestrian_light
Package pedestrianlight implements a pedestrian crossing signal with hierarchical states.
|
Package pedestrianlight implements a pedestrian crossing signal with hierarchical states. |
|
session_timeout
command
Package main demonstrates delayed (timed) transitions with a session timeout.
|
Package main demonstrates delayed (timed) transitions with a session timeout. |
|
text_editor
command
Package main demonstrates parallel (orthogonal) states with a text editor.
|
Package main demonstrates parallel (orthogonal) states with a text editor. |
|
Package generate provides Go code generation from Statekit Native JSON definitions.
|
Package generate provides Go code generation from Statekit Native JSON definitions. |
|
Package health provides liveness and readiness probes for statekit state machines.
|
Package health provides liveness and readiness probes for statekit state machines. |
|
Package http provides HTTP middleware and handlers for statekit state machines.
|
Package http provides HTTP middleware and handlers for statekit state machines. |
|
internal
|
|
|
parser
Package parser provides reflection-based parsing for struct-defined state machines.
|
Package parser provides reflection-based parsing for struct-defined state machines. |
|
Package lint provides static analysis for statekit state machines.
|
Package lint provides static analysis for statekit state machines. |
|
Package mcp provides an MCP (Model Context Protocol) server for creating, managing, and visualizing statekit state machines.
|
Package mcp provides an MCP (Model Context Protocol) server for creating, managing, and visualizing statekit state machines. |
|
Package metrics provides Prometheus metrics integration for statekit state machines.
|
Package metrics provides Prometheus metrics integration for statekit state machines. |
|
Package otel provides OpenTelemetry tracing integration for statekit state machines.
|
Package otel provides OpenTelemetry tracing integration for statekit state machines. |
|
Package plugin provides a hook system for extending interpreter behavior.
|
Package plugin provides a hook system for extending interpreter behavior. |
|
Package statetest provides utilities for testing statekit state machines.
|
Package statetest provides utilities for testing statekit state machines. |
|
Package viz provides visualization models and renderers for state machines.
|
Package viz provides visualization models and renderers for state machines. |
|
ascii
Package ascii provides ASCII/Unicode box diagram rendering for state machines.
|
Package ascii provides ASCII/Unicode box diagram rendering for state machines. |
|
goparser
Package goparser provides Go source code parsing to extract state machine definitions.
|
Package goparser provides Go source code parsing to extract state machine definitions. |
|
mermaid
Package mermaid provides Mermaid stateDiagram-v2 rendering for state machines.
|
Package mermaid provides Mermaid stateDiagram-v2 rendering for state machines. |
|
tui
Package tui provides an interactive terminal UI for visualizing state machines.
|
Package tui provides an interactive terminal UI for visualizing state machines. |