Documentation
¶
Overview ¶
Package machine is a nondeterministic, multi-state, clock-based, relational, optionally-accepting, and non-blocking state machine.
Index ¶
- Constants
- Variables
- func AMerge[K comparable, V any](maps ...map[K]V) map[K]V
- func IsActiveTick(tick uint64) bool
- func IsHandler(states S, method string) (string, string)
- func IsQueued(result Result) bool
- func ListHandlers(handlers any, states S) ([]string, error)
- func MockClock(mach *Machine, clock Clock)
- func MutationFormatArgs(matched map[string]string) string
- func NewLogArgsMapper(maxLen int, names []string) func(args A) map[string]string
- func NewStateGroups[G any](groups G, mixins ...any) G
- func NewStates[G States](states G) G
- func StatesEqual(states1 S, states2 S) bool
- func StatesToIndex(index S, states S) []int
- type A
- type AT
- type ATRpc
- type Api
- type CheckDone
- type Clock
- type CtxBinding
- type CtxKeyName
- type CtxValue
- type DefaultRelationsResolver
- func (rr *DefaultRelationsResolver) InboundRelationsOf(toState string) (S, error)
- func (rr *DefaultRelationsResolver) NewAutoMutation() (*Mutation, S)
- func (rr *DefaultRelationsResolver) NewSchema(schema Schema, states S)
- func (rr *DefaultRelationsResolver) RelationsBetween(fromState, toState string) ([]Relation, error)
- func (rr *DefaultRelationsResolver) RelationsOf(fromState string) ([]Relation, error)
- func (rr *DefaultRelationsResolver) SortStates(states S)
- func (rr *DefaultRelationsResolver) TargetStates(t *Transition, statesToSet, index S) S
- type Event
- type ExceptionArgsPanic
- type ExceptionHandler
- type HandlerChange
- type HandlerDispose
- type HandlerError
- type HandlerFinal
- type HandlerNegotiation
- type IndexStateCtx
- type IndexWhen
- type IndexWhenArgs
- type IndexWhenTime
- type InternalCheckFunc
- type InternalLogFunc
- type LastTxTracer
- type LogArgsMapperFn
- type LogEntry
- type LogLevel
- type LoggerFn
- type Machine
- func (m *Machine) ActiveStates(states S) S
- func (m *Machine) Add(states S, args A) Result
- func (m *Machine) Add1(state string, args A) Result
- func (m *Machine) AddBreakpoint(added S, removed S, strict bool)
- func (m *Machine) AddBreakpoint1(added string, removed string, strict bool)
- func (m *Machine) AddErr(err error, args A) Result
- func (m *Machine) AddErrState(state string, err error, args A) Result
- func (m *Machine) Any(states ...S) bool
- func (m *Machine) Any1(states ...string) bool
- func (m *Machine) Backoff() bool
- func (m *Machine) BindHandlers(handlers any) error
- func (m *Machine) BindTracer(tracer Tracer) error
- func (m *Machine) CanAdd(states S, args A) Result
- func (m *Machine) CanAdd1(state string, args A) Result
- func (m *Machine) CanRemove(states S, args A) Result
- func (m *Machine) CanRemove1(state string, args A) Result
- func (m *Machine) Clock(states S) Clock
- func (m *Machine) Context() context.Context
- func (m *Machine) DetachHandlers(handlers any) error
- func (m *Machine) DetachTracer(tracer Tracer) error
- func (m *Machine) Dispose()
- func (m *Machine) DisposeForce()
- func (m *Machine) Err() error
- func (m *Machine) EvAdd(event *Event, states S, args A) Result
- func (m *Machine) EvAdd1(event *Event, state string, args A) Result
- func (m *Machine) EvAddErr(event *Event, err error, args A) Result
- func (m *Machine) EvAddErrState(event *Event, state string, err error, args A) Result
- func (m *Machine) EvRemove(event *Event, states S, args A) Result
- func (m *Machine) EvRemove1(event *Event, state string, args A) Result
- func (m *Machine) EvToggle(e *Event, states S, args A) Result
- func (m *Machine) EvToggle1(e *Event, state string, args A) Result
- func (m *Machine) Eval(source string, fn func(), ctx context.Context) bool
- func (m *Machine) Export() (*Serialized, Schema, error)
- func (m *Machine) Fork(ctx context.Context, e *Event, fn func())
- func (m *Machine) Go(ctx context.Context, fn func())
- func (m *Machine) Groups() (map[string][]int, []string)
- func (m *Machine) Has(states S) bool
- func (m *Machine) Has1(state string) bool
- func (m *Machine) HasHandlers() bool
- func (m *Machine) Id() string
- func (m *Machine) Import(data *Serialized) error
- func (m *Machine) Index(states S) []int
- func (m *Machine) Index1(state string) int
- func (m *Machine) Inspect(states S) string
- func (m *Machine) Is(states S) bool
- func (m *Machine) Is1(state string) bool
- func (m *Machine) IsClock(clock Clock) bool
- func (m *Machine) IsDisposed() bool
- func (m *Machine) IsErr() bool
- func (m *Machine) IsQueued(mutType MutationType, states S, withoutArgsOnly bool, statesStrictEqual bool, ...) (found bool, idx uint16, qTick uint64)
- func (m *Machine) IsQueuedAbove(threshold int, mutType MutationType, states S, withoutArgsOnly bool, ...) bool
- func (m *Machine) IsTime(t Time, states S) bool
- func (m *Machine) Log(msg string, args ...any)
- func (m *Machine) MachineTick() uint32
- func (m *Machine) MustBindHandlers(handlers any)
- func (m *Machine) NewStateCtx(state string) context.Context
- func (m *Machine) Not(states S) bool
- func (m *Machine) Not1(state string) bool
- func (m *Machine) OnChange(fn HandlerChange)
- func (m *Machine) OnDispose(fn HandlerDispose)
- func (m *Machine) OnError(fn HandlerError)
- func (m *Machine) PanicToErr(args A)
- func (m *Machine) PanicToErrState(state string, args A)
- func (m *Machine) ParentId() string
- func (m *Machine) ParseStates(states S) S
- func (m *Machine) PrependMut(mut *Mutation) Result
- func (m *Machine) Queue() []*Mutation
- func (m *Machine) QueueLen() uint16
- func (m *Machine) QueueTick() uint64
- func (m *Machine) Remove(states S, args A) Result
- func (m *Machine) Remove1(state string, args A) Result
- func (m *Machine) Resolver() RelationsResolver
- func (m *Machine) Schema() Schema
- func (m *Machine) SchemaVer() int
- func (m *Machine) SemLogger() SemLogger
- func (m *Machine) Set(states S, args A) Result
- func (m *Machine) SetGroups(groups any, optStates States)
- func (m *Machine) SetGroupsString(groups map[string]S, order []string)
- func (m *Machine) SetSchema(newSchema Schema, names S) error
- func (m *Machine) SetTags(tags []string)
- func (m *Machine) StateNames() S
- func (m *Machine) StateNamesMatch(re *regexp.Regexp) S
- func (m *Machine) StatesVerified() bool
- func (m *Machine) String() string
- func (m *Machine) StringAll() string
- func (m *Machine) Switch(groups ...S) string
- func (m *Machine) Tags() []string
- func (m *Machine) Tick(state string) uint64
- func (m *Machine) Time(states S) Time
- func (m *Machine) Toggle(states S, args A) Result
- func (m *Machine) Toggle1(state string, args A) Result
- func (m *Machine) Tracers() []Tracer
- func (m *Machine) Transition() *Transition
- func (m *Machine) VerifyStates(states S) error
- func (m *Machine) WasClock(clock Clock) bool
- func (m *Machine) WasTime(t Time, states S) bool
- func (m *Machine) When(states S, ctx context.Context) <-chan struct{}
- func (m *Machine) When1(state string, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenArgs(state string, args A, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenDisposed() <-chan struct{}
- func (m *Machine) WhenErr(disposeCtx context.Context) <-chan struct{}
- func (m *Machine) WhenNot(states S, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenNot1(state string, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenQuery(clockCheck func(clock Clock) bool, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenQueue(tick Result) <-chan struct{}
- func (m *Machine) WhenQueueEnds() <-chan struct{}
- func (m *Machine) WhenTicks(state string, ticks int, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenTime(states S, times Time, ctx context.Context) <-chan struct{}
- func (m *Machine) WhenTime1(state string, ticks uint64, ctx context.Context) <-chan struct{}
- func (m *Machine) WillBe(states S, position ...Position) bool
- func (m *Machine) WillBe1(state string, position ...Position) bool
- func (m *Machine) WillBeRemoved(states S, position ...Position) bool
- func (m *Machine) WillBeRemoved1(state string, position ...Position) bool
- type MutSource
- type Mutation
- func (m *Mutation) CalledIndex(index S) *TimeIndex
- func (m *Mutation) IsCalled(idx int) bool
- func (m *Mutation) LogArgs(mapper LogArgsMapperFn) string
- func (m *Mutation) MapArgs(mapper LogArgsMapperFn) map[string]string
- func (m *Mutation) String() string
- func (m *Mutation) StringFromIndex(index S) string
- type MutationType
- type Opts
- type Position
- type Relation
- type RelationsResolver
- type Result
- type S
- type Schema
- type SemConfig
- type SemLogger
- type Serialized
- type State
- type StateIsActive
- type States
- type StatesBase
- type Step
- type StepType
- type Subscriptions
- func (sm *Subscriptions) HasWhenArgs() bool
- func (sm *Subscriptions) NewStateCtx(state string) context.Context
- func (sm *Subscriptions) ProcessStateCtx(deactivated S) []context.CancelFunc
- func (sm *Subscriptions) ProcessWhen(activated, deactivated S) []chan struct{}
- func (sm *Subscriptions) ProcessWhenArgs(e *Event) []chan struct{}
- func (sm *Subscriptions) ProcessWhenQuery() []chan struct{}
- func (sm *Subscriptions) ProcessWhenQueue(queueTick uint64) []chan struct{}
- func (sm *Subscriptions) ProcessWhenQueueEnds() []chan struct{}
- func (sm *Subscriptions) ProcessWhenTime(before Clock) []chan struct{}
- func (sm *Subscriptions) QueueFlush()
- func (sm *Subscriptions) SetClock(clock Clock)
- func (sm *Subscriptions) When(states S, ctx context.Context) <-chan struct{}
- func (sm *Subscriptions) WhenArgs(state string, args A, ctx context.Context) <-chan struct{}
- func (sm *Subscriptions) WhenNot(states S, ctx context.Context) <-chan struct{}
- func (sm *Subscriptions) WhenQuery(fn func(clock Clock) bool, ctx context.Context) <-chan struct{}
- func (sm *Subscriptions) WhenQueue(tick Result) <-chan struct{}
- func (sm *Subscriptions) WhenQueueEnds() <-chan struct{}
- func (sm *Subscriptions) WhenTime(states S, times Time, ctx context.Context) <-chan struct{}
- type Time
- func (t Time) ActiveStates(idxs []int) []int
- func (t Time) Add(t2 Time) Time
- func (t Time) After(orEqual bool, time2 Time) bool
- func (t Time) Any(idxs ...[]int) bool
- func (t Time) Any1(idxs ...int) bool
- func (t Time) Before(orEqual bool, time2 Time) bool
- func (t Time) DiffSince(before Time) Time
- func (t Time) Equal(strict bool, time2 Time) bool
- func (t Time) Filter(idxs []int) Time
- func (t Time) Increment(idx int) Time
- func (t Time) Is(idxs []int) bool
- func (t Time) Is1(idx int) bool
- func (t Time) NonZeroStates() []int
- func (t Time) Not(idxs []int) bool
- func (t Time) Not1(idx int) bool
- func (t Time) String() string
- func (t Time) Sum(idxs []int) uint64
- func (t Time) Tick(idx int) uint64
- func (t Time) ToIndex(index S) *TimeIndex
- type TimeIndex
- func (t TimeIndex) ActiveStates(states S) S
- func (t TimeIndex) Any(states ...string) bool
- func (t TimeIndex) Any1(states ...string) bool
- func (t TimeIndex) Filter(states S) *TimeIndex
- func (t TimeIndex) Is(states S) bool
- func (t TimeIndex) Is1(state string) bool
- func (t TimeIndex) NonZeroStates() S
- func (t TimeIndex) Not(states S) bool
- func (t TimeIndex) Not1(state string) bool
- func (t TimeIndex) StateName(idx int) string
- func (t TimeIndex) String() string
- func (t TimeIndex) Sum(states S) uint64
- type Tracer
- type TracerNoOp
- func (t *TracerNoOp) HandlerEnd(transition *Transition, emitter string, handler string)
- func (t *TracerNoOp) HandlerStart(transition *Transition, emitter string, handler string)
- func (t *TracerNoOp) Inheritable() bool
- func (t *TracerNoOp) MachineDispose(machID string)
- func (t *TracerNoOp) MachineInit(machine Api) context.Context
- func (t *TracerNoOp) MutationQueued(machine Api, mutation *Mutation)
- func (t *TracerNoOp) NewSubmachine(parent, machine Api)
- func (t *TracerNoOp) QueueEnd(machine Api)
- func (t *TracerNoOp) SchemaChange(machine Api, old Schema)
- func (t *TracerNoOp) TransitionEnd(transition *Transition)
- func (t *TracerNoOp) TransitionInit(transition *Transition)
- func (t *TracerNoOp) TransitionStart(transition *Transition)
- func (t *TracerNoOp) VerifyStates(machine Api)
- type Transition
- func (t *Transition) Args() A
- func (t *Transition) CalledStates() S
- func (t *Transition) CleanCache()
- func (t *Transition) ClockAfter() Clock
- func (t *Transition) ClockBefore() Clock
- func (t *Transition) IsAuto() bool
- func (t *Transition) IsHealth() bool
- func (t *Transition) StatesBefore() S
- func (t *Transition) String() string
- func (t *Transition) TargetStates() S
- func (t *Transition) TimeIndexAfter() *TimeIndex
- func (t *Transition) TimeIndexBefore() *TimeIndex
- func (t *Transition) TimeIndexCalled() *TimeIndex
- func (t *Transition) TimeIndexDiff() (*TimeIndex, *TimeIndex)
- func (t *Transition) TimeIndexTouched() *TimeIndex
- func (t *Transition) Type() MutationType
- type WhenArgsBinding
- type WhenBinding
- type WhenTimeBinding
Examples ¶
Constants ¶
const ( // EnvAmDebug enables a simple debugging mode (eg long timeouts). // "2" logs to stdout (where applicable) // "1" | "2" | "" (default) EnvAmDebug = "AM_DEBUG" // EnvAmTestRunner indicates a CI test runner. EnvAmTestRunner = "AM_TEST_RUNNER" // EnvAmLog sets the log level. // "1" | "2" | "3" | "4" | "5" | "" (default) EnvAmLog = "AM_LOG" // EnvAmDetectEval detects evals directly in handlers (use in tests). EnvAmDetectEval = "AM_DETECT_EVAL" // EnvAmTraceFilter will remove its contents from stack traces, shortening // them . EnvAmTraceFilter = "AM_TRACE_FILTER" // EnvAmTestDebug activates debugging in tests. EnvAmTestDebug = "AM_TEST_DEBUG" // EnvAmTestDbgAddr enables test loop integration (no parallel and dbg relay) EnvAmTestDbgAddr = "AM_TEST_DBG_ADDR" SuffixEnter = "Enter" SuffixExit = "Exit" SuffixState = "State" SuffixEnd = "End" PrefixErr = "Err" // StateAny is a name of a meta-state used in catch-all handlers. StateAny = "Any" // StateException is the name of the predefined Exception state. StateException = "Exception" // StateHeartbeat is the name of the predefined Heartbeat state. StateHeartbeat = "Heartbeat" // StateHealthcheck is the name of the predefined Healthcheck state. StateHealthcheck = "Healthcheck" // StateStart is the name of the predefined Start state. StateStart = "Start" // StateDisposing is the name of the predefined Disposing state. StateDisposing = "Disposing" // StateReady is the name of the predefined Ready state. StateReady = "Ready" // StateMachineRestored is the name of the predefined MachineRestored state. StateMachineRestored = "MachineRestored" )
Variables ¶
var ( // ErrStateUnknown indicates that the state is unknown. ErrStateUnknown = errors.New("state unknown") // ErrStateInactive indicates that a necessary state isn't active. ErrStateInactive = errors.New("state not active") // ErrCanceled indicates that a transition was canceled. ErrCanceled = errors.New("transition canceled") // ErrQueued indicates that a mutation was queued. Queuing is a feature, not // an error, but it may be considered as such in certain cases. ErrQueued = errors.New("transition queued") // ErrInvalidArgs indicates that arguments are invalid. ErrInvalidArgs = errors.New("invalid arguments") // ErrHandlerTimeout indicates that a mutation timed out. ErrHandlerTimeout = errors.New("handler timeout") // ErrEvalTimeout indicates that an eval func timed out. ErrEvalTimeout = errors.New("eval timeout") // ErrTimeout indicates that a generic timeout occurred. ErrTimeout = errors.New("timeout") // ErrStateMissing indicates that states are missing. ErrStateMissing = errors.New("missing states") // ErrRelation indicates that a relation definition is invalid. ErrRelation = errors.New("relation error") // ErrDisposed indicates that the machine has been disposed. ErrDisposed = errors.New("machine disposed") // ErrSchema indicates an issue with the machine schema. ErrSchema = errors.New("schema error") // ErrInternal happens for internal errors in the machine. These should be // reported as bugs. ErrInternal = errors.New("internal error") )
var CtxKey = &CtxKeyName{}
var LogArgs = []string{
"name", "id", "port", "addr", "err", "path", "url",
"uri",
}
LogArgs is a list of common argument names to be logged. Useful for debugging.
var LogArgsMaxLen = 20
LogArgsMaxLen is the default maximum length of the arg's string representation.
Functions ¶
func AMerge ¶ added in v0.9.0
func AMerge[K comparable, V any](maps ...map[K]V) map[K]V
AMerge merges 2 or more maps into 1. Useful for passing args from many packages.
func IsActiveTick ¶ added in v0.5.0
IsActiveTick returns true if the tick represents an active state (odd number).
func IsHandler ¶ added in v0.8.0
IsHandler checks if a method name is a handler method, by returning a state name.
func IsQueued ¶ added in v0.15.0
IsQueued returns true if the mutation has been queued, and the result represents the queue time it will be processed.
func ListHandlers ¶ added in v0.8.0
ListHandlers returns a list of handler method names from a handler struct, limited to [states].
func MockClock ¶ added in v0.7.0
MockClock mocks the internal clock of the machine. Only for testing.
func MutationFormatArgs ¶ added in v0.15.0
func NewLogArgsMapper ¶ added in v0.18.0
NewLogArgsMapper returns a matcher function for [Opts.LogArgs]. Useful for debugging untyped argument maps. Usually [names] extend defaults from LogArgs.
maxLen: maximum length of the arg's string representation). Defaults to LogArgsMaxLen,
func NewStateGroups ¶ added in v0.8.0
func StatesEqual ¶ added in v0.8.0
StatesEqual returns true if states1 and states2 are equal, regardless of order.
func StatesToIndex ¶ added in v0.12.0
StatesToIndex returns a subset of [index] that matches [states]. Unknown states are represented by -1.
Types ¶
type A ¶
A (arguments) is a map of named arguments for a Mutation.
type AT ¶ added in v0.8.0
type AT struct {
Err error
ErrTrace string
Panic *ExceptionArgsPanic
TargetStates S
CalledStates S
TimeBefore Time
TimeAfter Time
Event *Event
// MutDone chan gets closed by the machine once it's processed. Can cause chan
// leaks when misused. Only for Can* checks.
CheckDone *CheckDone
}
AT represents typed arguments of pkg/machine, extracted from Event.Args via ParseArgs, or created manually to for Pass.
type Api ¶ added in v0.8.0
type Api interface {
// Add1 is [Machine.Add1].
Add1(state string, args A) Result
// Add is [Machine.Add].
Add(states S, args A) Result
// Remove1 is [Machine.Remove1].
Remove1(state string, args A) Result
// Remove is [Machine.Remove].
Remove(states S, args A) Result
// AddErr is [Machine.AddErr].
AddErr(err error, args A) Result
// AddErrState is [Machine.AddErrState].
AddErrState(state string, err error, args A) Result
// Toggle is [Machine.Toggle].
Toggle(states S, args A) Result
// Toggle1 is [Machine.Toggle1].
Toggle1(state string, args A) Result
// Set is [Machine.Set].
Set(states S, args A) Result
// EvAdd1 is [Machine.EvAdd1].
EvAdd1(event *Event, state string, args A) Result
// EvAdd is [Machine.EvAdd].
EvAdd(event *Event, states S, args A) Result
// EvRemove1 is [Machine.EvRemove1].
EvRemove1(event *Event, state string, args A) Result
// EvRemove is [Machine.EvRemove].
EvRemove(event *Event, states S, args A) Result
// EvAddErr is [Machine.EvAddErr].
EvAddErr(event *Event, err error, args A) Result
// EvAddErrState is [Machine.EvAddErrState].
EvAddErrState(event *Event, state string, err error, args A) Result
// EvToggle is [Machine.Toggle].
EvToggle(event *Event, states S, args A) Result
// EvToggle1 is [Machine.Toggle1].
EvToggle1(event *Event, state string, args A) Result
// WhenArgs is [Machine.WhenArgs].
WhenArgs(state string, args A, ctx context.Context) <-chan struct{}
// Err is [Machine.Err].
Err() error
// IsErr is [Machine.IsErr].
IsErr() bool
// Is is [Machine.Is].
Is(states S) bool
// Is1 is [Machine.Is1].
Is1(state string) bool
// Any is [Machine.Any].
Any(states ...S) bool
// Any1 is [Machine.Any1].
Any1(state ...string) bool
// Not is [Machine.Not].
Not(states S) bool
// Not1 is [Machine.Not1].
Not1(state string) bool
// IsTime is [Machine.IsTime].
IsTime(time Time, states S) bool
// WasTime is [Machine.WasTime].
WasTime(time Time, states S) bool
// IsClock is [Machine.IsClock].
IsClock(clock Clock) bool
// WasClock is [Machine.WasClock].
WasClock(clock Clock) bool
// Has is [Machine.Has].
Has(states S) bool
// Has1 is [Machine.Has1].
Has1(state string) bool
// CanAdd is [Machine.CanAdd].
CanAdd(states S, args A) Result
// CanAdd1 is [Machine.CanAdd1].
CanAdd1(state string, args A) Result
// CanRemove is [Machine.CanRemove].
CanRemove(states S, args A) Result
// CanRemove1 is [Machine.CanRemove1].
CanRemove1(state string, args A) Result
// Transition is [Machine.Transition].
Transition() *Transition
// When is [Machine.When].
When(states S, ctx context.Context) <-chan struct{}
// When1 is [Machine.When1].
When1(state string, ctx context.Context) <-chan struct{}
// WhenNot is [Machine.WhenNot].
WhenNot(states S, ctx context.Context) <-chan struct{}
// WhenNot1 is [Machine.WhenNot1].
WhenNot1(state string, ctx context.Context) <-chan struct{}
// WhenTime is [Machine.WhenTime].
WhenTime(states S, times Time, ctx context.Context) <-chan struct{}
// WhenTime1 is [Machine.WhenTime1].
WhenTime1(state string, tick uint64, ctx context.Context) <-chan struct{}
// WhenTicks is [Machine.WhenTicks].
WhenTicks(state string, ticks int, ctx context.Context) <-chan struct{}
// WhenQuery is [Machine.WhenQuery].
WhenQuery(query func(clock Clock) bool, ctx context.Context) <-chan struct{}
// WhenErr is [Machine.WhenErr].
WhenErr(ctx context.Context) <-chan struct{}
// WhenQueue is [Machine.WhenQueue].
WhenQueue(tick Result) <-chan struct{}
// StateNames is [Machine.StateNames].
StateNames() S
// StateNamesMatch is [Machine.StateNamesMatch].
StateNamesMatch(re *regexp.Regexp) S
// ActiveStates is [Machine.ActiveStates].
ActiveStates(states S) S
// Tick is [Machine.Tick].
Tick(state string) uint64
// Clock is [Machine.Clock].
Clock(states S) Clock
// Time is [Machine.Time].
Time(states S) Time
// QueueTick is [Machine.QueueTick].
QueueTick() uint64
// MachineTick is [Machine.MachineTick].
MachineTick() uint32
// QueueLen is [Machine.QueueLen].
QueueLen() uint16
// NewStateCtx is [Machine.NewStateCtx].
NewStateCtx(state string) context.Context
// Export is [Machine.Export].
Export() (*Serialized, Schema, error)
// Schema is [Machine.Schema].
Schema() Schema
// Switch is [Machine.Switch].
Switch(groups ...S) string
// Groups is [Machine.Groups].
Groups() (map[string][]int, []string)
// Index is [Machine.Index].
Index(states S) []int
// Index1 is [Machine.Index1].
Index1(state string) int
// Id is [Machine.Id].
Id() string
// ParentId is [Machine.ParentId].
ParentId() string
// ParseStates is [Machine.ParseStates].
ParseStates(states S) S
// Tags is [Machine.Tags].
Tags() []string
// Ctx is [Machine.Ctx].
Context() context.Context
// String is [Machine.String].
String() string
// StringAll is [Machine.StringAll].
StringAll() string
// Log is [Machine.Log].
Log(msg string, args ...any)
// SemLogger is [Machine.SemLogger].
SemLogger() SemLogger
// Inspect is [Machine.Inspect].
Inspect(states S) string
// BindHandlers is [Machine.BindHandlers].
BindHandlers(handlers any) error
// DetachHandlers is [Machine.DetachHandlers].
DetachHandlers(handlers any) error
// HasHandlers is [Machine.HasHandlers].
HasHandlers() bool
// StatesVerified is [Machine.StatesVerified].
StatesVerified() bool
// Tracers is [Machine.Tracers].
Tracers() []Tracer
// DetachTracer is [Machine.DetachTracer].
DetachTracer(tracer Tracer) error
// BindTracer is [Machine.BindTracer].
BindTracer(tracer Tracer) error
// AddBreakpoint is [Machine.AddBreakpoint].
AddBreakpoint(added S, removed S, strict bool)
// AddBreakpoint1 is [Machine.AddBreakpoint1].
AddBreakpoint1(added string, removed string, strict bool)
// Dispose is [Machine.Dispose].
Dispose()
// WhenDisposed is [Machine.WhenDisposed].
WhenDisposed() <-chan struct{}
// IsDisposed is [Machine.IsDisposed].
IsDisposed() bool
// OnDispose is [Machine.OnDispose].
OnDispose(fn HandlerDispose)
}
Api is a subset of Machine for alternative implementations.
type CheckDone ¶ added in v0.15.0
type CheckDone struct {
// TODO close these on dispose and deadline
Ch chan struct{}
// Was the mutation canceled?
Canceled bool
}
type Clock ¶ added in v0.7.0
Clock is a map of state names to their tick values. It's like Time but indexed by string, instead of int. See TimeIndex for a more advanced data structure.
type CtxBinding ¶ added in v0.8.0
type CtxBinding struct {
Ctx context.Context
Cancel context.CancelFunc
}
type CtxKeyName ¶ added in v0.8.0
type CtxKeyName struct{}
type DefaultRelationsResolver ¶
type DefaultRelationsResolver struct {
// TODO replace with TimeIndex, log(), Schema
// - for netmach mut filtering
// - for alternative impls
Machine *Machine
Transition *Transition
Index S
// contains filtered or unexported fields
}
DefaultRelationsResolver is the default implementation of the RelationsResolver with Add, Remove, Require and After. It can be overridden using Opts.Resolver. TODO refac RelationsDefault
func (*DefaultRelationsResolver) InboundRelationsOf ¶ added in v0.12.0
func (rr *DefaultRelationsResolver) InboundRelationsOf(toState string) ( S, error, )
InboundRelationsOf returns a list of states pointing to [toState]. Not thread safe.
func (*DefaultRelationsResolver) NewAutoMutation ¶ added in v0.12.0
func (rr *DefaultRelationsResolver) NewAutoMutation() (*Mutation, S)
NewAutoMutation implements RelationsResolver.GetAutoMutation.
func (*DefaultRelationsResolver) NewSchema ¶ added in v0.12.0
func (rr *DefaultRelationsResolver) NewSchema(schema Schema, states S)
func (*DefaultRelationsResolver) RelationsBetween ¶ added in v0.12.0
func (rr *DefaultRelationsResolver) RelationsBetween( fromState, toState string, ) ([]Relation, error)
RelationsBetween returns a list of outbound relations between fromState -> toState. Not thread safe.
func (*DefaultRelationsResolver) RelationsOf ¶ added in v0.12.0
func (rr *DefaultRelationsResolver) RelationsOf(fromState string) ( []Relation, error, )
RelationsOf returns a list of relation types of the given state. Not thread safe.
func (*DefaultRelationsResolver) SortStates ¶
func (rr *DefaultRelationsResolver) SortStates(states S)
SortStates implements RelationsResolver.SortStates.
func (*DefaultRelationsResolver) TargetStates ¶ added in v0.12.0
func (rr *DefaultRelationsResolver) TargetStates( t *Transition, statesToSet, index S, ) S
TargetStates implements RelationsResolver.TargetStates.
type Event ¶
type Event struct {
// Ctx is an optional context this event is constrained by.
Ctx context.Context
// Name of the handler method (eg FooState).
Name string
// MachineId is the ID of the parent machine.
MachineId string
// TransitionId is the ID of the parent transition.
TransitionId string
// Args is a map of named arguments for a Mutation.
Args A
// IsCheck is true if this event is a check event, fired by one of Can*()
// methods. Useful for avoiding flooding the log with errors.
IsCheck bool
// contains filtered or unexported fields
}
Event struct represents a single event of a Mutation within a Transition. One event can have 0-n handlers.
func NewEvent ¶ added in v0.17.0
NewEvent creates a new Event struct with private fields initialized.
func (*Event) Export ¶ added in v0.15.0
Export clones only the essential data of the Event. Useful for tracing vs GC.
func (*Event) IsValid ¶ added in v0.10.1
IsValid confirm this event should still be processed. Useful for negotiation handlers, which can't use state context.
func (*Event) Transition ¶ added in v0.5.0
func (e *Event) Transition() *Transition
Transition returns the Transition of an Event.
type ExceptionArgsPanic ¶
type ExceptionArgsPanic struct {
CalledStates S
StatesBefore S
Transition *Transition
LastStep *Step
StackTrace string
}
ExceptionArgsPanic is an optional argument ["panic"] for the StateException state which describes a panic within a Transition handler.
type ExceptionHandler ¶
type ExceptionHandler struct{}
ExceptionHandler provide a basic StateException state support, as should be embedded into handler structs in most of the cases. Because ExceptionState will be called after [Machine.HandlerDeadline], it should handle locks on its own (to not race with itself).
func (*ExceptionHandler) ExceptionState ¶
func (eh *ExceptionHandler) ExceptionState(e *Event)
ExceptionState is a final entry handler for the StateException state. Args: - err error: The error that caused the StateException state. - panic *ExceptionArgsPanic: Optional details about the panic.
type HandlerChange ¶ added in v0.15.0
type HandlerDispose ¶ added in v0.9.0
HandlerDispose is a machine disposal handler func signature.
type HandlerError ¶ added in v0.13.0
type HandlerFinal ¶ added in v0.8.0
type HandlerFinal func(e *Event)
HandlerFinal is a final transition handler func signature.
type HandlerNegotiation ¶ added in v0.8.0
HandlerNegotiation is a negotiation transition handler func signature.
type IndexStateCtx ¶ added in v0.7.0
type IndexStateCtx map[string]*CtxBinding
IndexStateCtx is a map of (single) state names to a context cancel function
type IndexWhen ¶ added in v0.7.0
type IndexWhen map[string][]*WhenBinding
IndexWhen is a map of (single) state names to a list of activation or de-activation bindings
type IndexWhenArgs ¶ added in v0.7.0
type IndexWhenArgs map[string][]*WhenArgsBinding
IndexWhenArgs is a map of (single) state names to a list of args value bindings
type IndexWhenTime ¶ added in v0.7.0
type IndexWhenTime map[string][]*WhenTimeBinding
IndexWhenTime is a map of (single) state names to a list of time bindings
type InternalCheckFunc ¶ added in v0.15.1
type InternalLogFunc ¶ added in v0.15.1
type LastTxTracer ¶ added in v0.12.0
type LastTxTracer struct {
*TracerNoOp
// contains filtered or unexported fields
}
TODO add TTL, ctx
func NewLastTxTracer ¶ added in v0.12.0
func NewLastTxTracer() *LastTxTracer
NewLastTxTracer returns a Tracer that logs the last transition.
func (*LastTxTracer) Load ¶ added in v0.12.0
func (t *LastTxTracer) Load() *Transition
Load returns the last transition.
func (*LastTxTracer) String ¶ added in v0.12.0
func (t *LastTxTracer) String() string
func (*LastTxTracer) TransitionEnd ¶ added in v0.12.0
func (t *LastTxTracer) TransitionEnd(transition *Transition)
type LogArgsMapperFn ¶ added in v0.15.0
LogArgsMapperFn is a function that maps arguments to be logged. Useful for debugging. See NewLogArgsMapper.
type LogLevel ¶
type LogLevel int
LogLevel defines the level of details in the produced log (0-5).
const ( // LogNothing means no logging, including external msgs. LogNothing LogLevel = iota // LogExternal will show ony external user msgs. LogExternal // LogChanges means logging state changes and external msgs. LogChanges // LogOps means LogChanges + logging all the operations. LogOps // LogDecisions means LogOps + logging all the decisions behind them. LogDecisions // LogEverything means LogDecisions + all event and handler names, and more. LogEverything )
func EnvLogLevel ¶ added in v0.7.0
EnvLogLevel returns a log level from an environment variable, AM_LOG by default.
type Machine ¶
type Machine struct {
// Maximum number of mutations that can be queued. Default: 1000.
QueueLimit uint16
// HandlerTimeout defined the time for a handler to execute before it causes
// StateException. Default: 1s. See also [Opts.HandlerTimeout].
// Using HandlerTimeout can cause race conditions, unless paired with
// [Event.IsValid].
HandlerTimeout time.Duration
// HandlerDeadline is a grace period after a handler timeout, before the
// machine moves on.
HandlerDeadline time.Duration
// LastHandlerDeadline stores when the last HandlerDeadline was hit.
LastHandlerDeadline atomic.Pointer[time.Time]
// HandlerBackoff is the time after a [HandlerDeadline], during which the
// machine will return [Canceled] to any mutation.
HandlerBackoff time.Duration
// EvalTimeout is the time the machine will try to execute an eval func.
// Like any other handler, eval func also has [HandlerTimeout]. Default: 1s.
EvalTimeout time.Duration
// If true, the machine will log stack traces of errors. Default: true.
// Requires an ExceptionHandler binding and [Machine.PanicToException] set.
LogStackTrace bool
// If true, the machine will catch panic and trigger the [StateException]
// state. Default: true. Can be disabled via AM_DEBUG=1.
PanicToException bool
// DisposeTimeout specifies the duration to wait for the queue to drain during
// disposal. Default 1s.
DisposeTimeout time.Duration
// contains filtered or unexported fields
}
Machine provides a state machine API with mutations, state schema, handlers, subscriptions, tracers, and helpers methods. It also holds a queue of mutations to execute.
func New ¶
New creates a new Machine instance, bound to context and modified with optional Opts.
Example ¶
ctx := context.TODO()
mach := New(ctx, Schema{
"Foo": {Require: S{"Bar"}},
"Bar": {},
}, nil)
mach.Add1("Foo", nil)
mach.Is1("Foo") // false
func NewCommon ¶ added in v0.5.0
func NewCommon( ctx context.Context, id string, stateSchema Schema, stateNames S, handlers any, parent Api, opts *Opts, ) (*Machine, error)
NewCommon creates a new Machine instance with all the common options set.
Example ¶
// define (tip: use am-gen instead)
stateStruct := Schema{
"Foo": {Require: S{"Bar"}},
"Bar": {},
}
stateNames := []string{"Foo", "Bar"}
type Handlers struct{}
// func (h *Handlers) FooState(e *Event) {
// args := e.Args
// mach := e.Machine()
// ctx := mach.NewStateCtx("Foo")
// // unblock
// go func() {
// if ctx.Err() != nil {
// return // expired
// }
// // blocking calls...
// if ctx.Err() != nil {
// return // expired
// }
// mach.Add1("Bar", nil)
// }()
// }
// init
ctx := context.TODO()
mach, err := NewCommon(ctx, "mach-id",
stateStruct, stateNames,
&Handlers{}, nil, nil)
if err != nil {
panic(err)
}
mach.SemLogger().SetLevel(LogOps)
func (*Machine) ActiveStates ¶
ActiveStates returns a copy of the currently active states when states is nil, optionally limiting the results to a subset of states.
func (*Machine) Add ¶
Add activates a list of states in the machine, returning the result of the transition (Executed, Queued, Canceled). Like every mutation method, it will resolve relations and trigger handlers.
func (*Machine) Add1 ¶ added in v0.5.0
Add1 is a shorthand method to add a single state with the passed args. See Add().
func (*Machine) AddBreakpoint ¶ added in v0.8.0
AddBreakpoint adds a breakpoint for an outcome of mutation (added and removed states) checked by mutation equality. Once such a mutation happens, a log message will be printed out. We can set an IDE's breakpoint on this line and see the mutation's sync stack trace. If [Machine.LogStackTrace] is set, the stack trace will be printed out as well. Many breakpoints can be added, but none removed.
Breakpoints are useful to find the caller of a mutation, but don't work with Machine.Set.
strict: strict skips already active / inactive (for strict of diff equality).
func (*Machine) AddBreakpoint1 ¶ added in v0.15.0
func (*Machine) AddErr ¶
AddErr is a dedicated method to add the StateException state with the passed error and optional arguments. Like every mutation method, it will resolve relations and trigger handlers. AddErr produces a stack trace of the error, if LogStackTrace is enabled.
func (*Machine) AddErrState ¶ added in v0.7.0
AddErrState adds a dedicated error state, along with the build in StateException state. Like every mutation method, it will resolve relations and trigger handlers. AddErrState produces a stack trace of the error, if LogStackTrace is enabled.
func (*Machine) Any ¶
Any is a group call to Is, returns true if any of the params return true from Is.
machine.StringAll() // ()[Foo:0 Bar:0 Baz:0]
machine.Add(S{"Foo"})
// is(Foo, Bar) or is(Bar)
machine.Any(S{"Foo", "Bar"}, S{"Bar"}) // false
// is(Foo) or is(Bar)
machine.Any(S{"Foo"}, S{"Bar"}) // true
func (*Machine) Any1 ¶ added in v0.5.0
Any1 is group call to Machine.Is1, returns true if any of the params return true from Machine.Is1.
func (*Machine) Backoff ¶ added in v0.13.0
Backoff is true in case the machine had a recent HandlerDeadline. During a backoff, all mutations will be Canceled.
func (*Machine) BindHandlers ¶
BindHandlers binds a struct of handler methods to machine's states, based on the naming convention, eg `FooState(e *Event)`. Negotiation handlers can optionally return bool.
func (*Machine) BindTracer ¶ added in v0.8.0
BindTracer binds a Tracer to the machine. Tracers can cause StateException in submachines, before any handlers are bound. Use the Err() getter to examine such errors.
func (*Machine) CanAdd ¶ added in v0.5.0
CanAdd checks if [states] can be added and returns Executed or [AT.CheckDone] if a dry run mutation passes. Useful for reducing failed negotiations.
func (*Machine) CanAdd1 ¶ added in v0.15.0
CanAdd1 is Machine.CanAdd for a single state.
func (*Machine) CanRemove ¶ added in v0.5.0
CanRemove checks if [states] can be removed and returns Executed or [AT.CheckDone] if a dry run mutation passes. Useful for reducing failed negotiations.
func (*Machine) CanRemove1 ¶ added in v0.15.0
CanRemove1 is Machine.CanRemove for a single state.
func (*Machine) Clock ¶
Clock returns current machine's clock, a state-keyed map of ticks. If states are passed, only the ticks of the passed states are returned.
func (*Machine) Context ¶ added in v0.18.0
Context returns the machine's parent context. This context lives longer then the internal graceful dispose context.
func (*Machine) DetachHandlers ¶ added in v0.8.0
DetachHandlers detaches previously bound machine handlers.
func (*Machine) DetachTracer ¶ added in v0.8.0
DetachTracer tries to remove a tracer from the machine. Returns an error in case the tracer wasn't bound.
func (*Machine) Dispose ¶
func (m *Machine) Dispose()
Dispose disposes the machine and all its emitters. You can wait for the completion of the disposal with `<-mach.WhenDisposed()`. It's advised to use Dispose() func from pkg/helpers instead, which handles Disposed state mixing.
func (*Machine) DisposeForce ¶ added in v0.5.0
func (m *Machine) DisposeForce()
DisposeForce disposes the machine and all its emitters, without waiting for the queue to drain. Will cause panics.
func (*Machine) EvAdd ¶ added in v0.9.0
EvAdd is like Add, but passed the source event as the 1st param, which results in traceable transitions.
func (*Machine) EvAdd1 ¶ added in v0.9.0
EvAdd1 is like Add1 but passed the source event as the 1st param, which results in traceable transitions.
func (*Machine) EvAddErr ¶ added in v0.9.0
EvAddErr is like AddErr, but passed the source event as the 1st param, which results in traceable transitions.
func (*Machine) EvAddErrState ¶ added in v0.9.0
EvAddErrState is like AddErrState, but passed the source event as the 1st param, which results in traceable transitions.
func (*Machine) EvRemove ¶ added in v0.9.0
EvRemove is like Remove but passed the source event as the 1st param, which results in traceable transitions.
func (*Machine) EvRemove1 ¶ added in v0.9.0
EvRemove1 is like Remove1, but passed the source event as the 1st param, which results in traceable transitions.
func (*Machine) EvToggle ¶ added in v0.15.0
EvToggle is a traced version of Machine.Toggle.
func (*Machine) EvToggle1 ¶ added in v0.15.0
EvToggle1 is a traced version of Machine.Toggle1.
func (*Machine) Eval ¶ added in v0.5.0
Eval executes a function on the machine's queue, allowing to avoid using locks for non-handler code. Blocking code should NOT be scheduled here. Eval cannot be called within a handler's critical zone, as both are using the same serial queue and will deadlock. Eval has a timeout of HandlerTimeout/2 and will return false in case it happens. Evals do not trigger consensus, thus are much faster than state mutations.
ctx: nil context defaults to machine's context.
Note: usage of Eval is discouraged. But if you have to, use AM_DETECT_EVAL in tests for deadlock detection. Most usages of eval can be replaced with atomics or returning from mutation via channels. Evals can be better then Multi states in some cases.
func (*Machine) Export ¶ added in v0.6.4
func (m *Machine) Export() (*Serialized, Schema, error)
Export exports the machine state as Serialized: ID, machine time, and state names.
func (*Machine) Fork ¶ added in v0.18.0
Fork is a syntax sugar method for a handler unblocking boilerplate. Fork can only by used in the handler body (while the event is valid). See Machine.Go for nested forking.
func (*Machine) Go ¶ added in v0.18.0
Go is a syntax sugar method for a nested handler unblocking boilerplate.
func (*Machine) Has ¶
Has return true is passed states are registered in the machine. Useful for checking if a machine implements a specific state set.
func (*Machine) Has1 ¶ added in v0.5.0
Has1 is shorthand for Has. It returns true if the passed state is registered in the machine.
func (*Machine) HasHandlers ¶ added in v0.12.0
HasHandlers returns true if this machine has bound handlers, and thus an allocated goroutine. It also makes it nondeterministic.
func (*Machine) Import ¶ added in v0.6.4
func (m *Machine) Import(data *Serialized) error
Import imports the machine state from Serialized. It's not safe to import into a machine which has already produces transitions and/or has telemetry connected (use Machine.SetSchema instead).
func (*Machine) Index ¶ added in v0.7.0
Index returns a list of state indexes in the machine's StateNames() list, with -1s for missing ones.
func (*Machine) Index1 ¶ added in v0.12.0
Index1 returns the index of a state in the machine's StateNames() list, or -1 when not found or machine has been disposed.
func (*Machine) Inspect ¶
Inspect returns a multi-line string representation of the machine (states, relations, clocks). states: param for ordered or partial results.
func (*Machine) Is ¶
Is checks if all the passed states are currently active.
machine.StringAll() // ()[Foo:0 Bar:0 Baz:0]
machine.Add(S{"Foo"})
machine.Is(S{"Foo"}) // true
machine.Is(S{"Foo", "Bar"}) // false
func (*Machine) Is1 ¶ added in v0.5.0
Is1 is Machine.Is for a single state.
func (*Machine) IsClock ¶
IsClock checks if the machine has changed since the passed clock. Returns true if at least one state has changed.
func (*Machine) IsDisposed ¶ added in v0.8.0
IsDisposed returns true if the machine has been disposed.
func (*Machine) IsQueued ¶
func (m *Machine) IsQueued(mutType MutationType, states S, withoutArgsOnly bool, statesStrictEqual bool, minQueueTick uint64, isCheck bool, position Position, ) (found bool, idx uint16, qTick uint64)
IsQueued checks if a particular mutation has been queued. Returns an index (idx, true), or (0, false), if not found.
mutType: add, remove, set
states: list of states used in the mutation
withoutArgsOnly: matches only mutation without the arguments object
statesStrictEqual: states of the mutation have to be exactly like `states` and not a superset.
minQueueTick: minimal queue tick assigned to the matched mutation
isCheck: the mutation has to be a [Mutation.IsCheck]
position: position in the queue, after applying the [startIndex]
func (*Machine) IsQueuedAbove ¶ added in v0.13.0
func (m *Machine) IsQueuedAbove(threshold int, mutType MutationType, states S, withoutArgsOnly bool, statesStrictEqual bool, minQueueTick uint64, ) bool
IsQueuedAbove ... N times. This method allows for rate-limiting of mutations for specific states and a threshold.
func (*Machine) IsTime ¶ added in v0.7.0
IsTime checks if the machine has changed since the passed time (list of ticks). Returns true if at least one state has changed. The states param is optional and can be used to check only a subset of states.
func (*Machine) Log ¶
Log logs an [extern] message unless LogNothing is set. Optionally redirects to a custom logger from SemLogger().SetLogger.
func (*Machine) MachineTick ¶ added in v0.16.0
MachineTick is the number of times the machine has been started. Each start means an empty queue. Only set by Machine.Import.
func (*Machine) MustBindHandlers ¶ added in v0.8.0
MustBindHandlers is a panicking version of BindHandlers, useful in tests.
func (*Machine) NewStateCtx ¶ added in v0.5.0
NewStateCtx returns a new sub-context, bound to the current clock's tick of the passed state.
Context cancels when the state has been deactivated, or right away, if it isn't currently active.
State contexts are used to check state expirations and should be checked often inside goroutines.
func (*Machine) Not ¶
Not checks if **none** of the passed states are currently active.
machine.StringAll()
// -> ()[A:0 B:0 C:0 D:0]
machine.Add(S{"A", "B"})
// not(A) and not(C)
machine.Not(S{"A", "C"})
// -> false
// not(C) and not(D)
machine.Not(S{"C", "D"})
// -> true
func (*Machine) Not1 ¶ added in v0.5.0
Not1 is Machine.Not for a single state.
func (*Machine) OnChange ¶ added in v0.13.0
func (m *Machine) OnChange(fn HandlerChange)
OnChange is the most basic state-change handler, useful for machines without any handlers.
func (*Machine) OnDispose ¶ added in v0.16.0
func (m *Machine) OnDispose(fn HandlerDispose)
OnDispose adds a function to be called after the machine gets disposed. These functions will run synchronously just before WhenDisposed() channel gets closed. Considering it's a low-level feature, it's advised to handle disposal via dedicated states.
func (*Machine) OnError ¶ added in v0.13.0
func (m *Machine) OnError(fn HandlerError)
OnError is the most basic error handler, useful for machines without any handlers.
func (*Machine) PanicToErr ¶ added in v0.7.0
PanicToErr will catch a panic and add the StateException state. Needs to be called in a defer statement, just like a recover() call.
func (*Machine) PanicToErrState ¶ added in v0.7.0
PanicToErrState will catch a panic and add the StateException state, along with the passed state. Needs to be called in a defer statement, just like a recover() call.
func (*Machine) ParseStates ¶ added in v0.16.0
ParseStates parses a list of states, removing unknown ones and duplicates. Use Machine.Has and Machine.Has1 to check if a state is defined for the machine.
func (*Machine) PrependMut ¶ added in v0.15.0
PrependMut prepends the mutation to the front of the queue. This is a special cases only method and should be used with caution, as it can create an infinite loop. It's useful for postponing mutations inside a negotiation handler. The returned Result can't be waited on, as prepended mutations don't create a queue tick.
func (*Machine) QueueTick ¶ added in v0.15.0
QueueTick is the number of times the queue has processed a mutation. Starts from [1], for easy comparison with Result.
func (*Machine) Remove ¶
Remove deactivates a list of states in the machine, returning the result of the transition (Executed, Queued, Canceled). Like every mutation method, it will resolve relations and trigger handlers.
func (*Machine) Remove1 ¶ added in v0.5.0
Remove1 is Machine.Remove1 for a single state.
func (*Machine) Resolver ¶
func (m *Machine) Resolver() RelationsResolver
Resolver returns the relation resolver, used to produce target states of transitions.
func (*Machine) Set ¶
Set deactivates a list of states in the machine, returning the result of the transition (Executed, Canceled, Queued). Like every mutation method, it will resolve relations and trigger handlers.
func (*Machine) SetGroups ¶ added in v0.15.0
SetGroups organizes the schema into a tree using schema-v2 structs.
func (*Machine) SetGroupsString ¶ added in v0.15.0
SetGroupsString is like SetGroups, but work with the schema-v1 format.
func (*Machine) SetSchema ¶ added in v0.11.0
SetSchema sets the machine's schema. It will automatically call VerifyStates with the names param and handle EventSchemaChange if successful. The new schema has to be longer than the previous one (no relations-only changes). The length of the schema is also the version of the schema.
func (*Machine) SetTags ¶ added in v0.10.1
SetTags updates the machine's tags with the provided slice of strings.
func (*Machine) StateNames ¶
StateNames returns a SHARED copy of all the state names.
func (*Machine) StateNamesMatch ¶ added in v0.12.0
TODO docs
func (*Machine) StatesVerified ¶ added in v0.5.0
StatesVerified returns true if the state names have been ordered using VerifyStates.
func (*Machine) String ¶
String returns a one line representation of the currently active states, with their clock values. Inactive states are omitted. Eg: (Foo:1 Bar:3)
func (*Machine) StringAll ¶
StringAll returns a one line representation of all the states, with their clock values. Inactive states are in square brackets.
(Foo:1 Bar:3) [Baz:2]
func (*Machine) Switch ¶ added in v0.3.0
Switch returns the first state from the passed list that is currently active, making it handy for switch statements. Useful for state groups.
switch mach.Switch(ss.GroupPlaying) {
case "Playing":
case "Paused":
case "Stopped":
}
func (*Machine) Tags ¶ added in v0.5.0
Tags returns machine's tags, a list of unstructured strings without spaces.
func (*Machine) Time ¶
Time returns machine's time, a list of ticks per state. Returned value includes the specified states, or all the states if nil.
func (*Machine) Toggle ¶ added in v0.10.1
Toggle deactivates a list of states in case all are active, or activates them otherwise. Returns the result of the transition (Executed, Queued, Canceled).
func (*Machine) Toggle1 ¶ added in v0.8.0
Toggle1 activates or deactivates a single state, depending on its current state. Returns the result of the transition (Executed, Queued, Canceled).
func (*Machine) Transition ¶
func (m *Machine) Transition() *Transition
Transition returns the current transition, if any.
func (*Machine) VerifyStates ¶ added in v0.3.0
VerifyStates verifies an array of state names and returns an error in case at least one isn't defined. It also retains the order and uses it for StateNames. Verification can be checked via Machine.StatesVerified.
func (*Machine) WasClock ¶ added in v0.12.0
WasClock checks if the passed time has happened (or happening right now). Returns false if at least one state is too early.
func (*Machine) WasTime ¶ added in v0.12.0
WasTime checks if the passed time has happened (or happening right now). Returns false if at least one state is too early. The states param is optional and can be used to check only a subset of states.
func (*Machine) When ¶
When returns a channel that will be closed when all the passed states become active or the machine gets disposed.
ctx: optional context that will close the channel early.
func (*Machine) WhenArgs ¶ added in v0.5.0
WhenArgs returns a channel that will be closed when the passed state becomes active with all the passed args. Args are compared using the native '=='. It's meant to be used with async Multi states, to filter out a specific call.
ctx: optional context that will close the channel when handler loop ends.
func (*Machine) WhenDisposed ¶ added in v0.5.0
func (m *Machine) WhenDisposed() <-chan struct{}
WhenDisposed returns a channel that will be closed when the machine is disposed.
func (*Machine) WhenErr ¶
WhenErr returns a channel that will be closed when the machine is in the StateException state.
ctx: optional context that will close the channel early.
func (*Machine) WhenNot ¶
WhenNot returns a channel that will be closed when all the passed states become inactive or the machine gets disposed.
ctx: optional context that will close the channel early.
func (*Machine) WhenNot1 ¶ added in v0.5.0
WhenNot1 is an alias to WhenNot() for a single state. See WhenNot.
func (*Machine) WhenQuery ¶ added in v0.16.0
func (m *Machine) WhenQuery( clockCheck func(clock Clock) bool, ctx context.Context, ) <-chan struct{}
WhenQuery returns a channel that will be closed when the passed [clockCheck] function returns true. [clockCheck] should be a pure function and non-blocking.`
ctx: optional context that will close the channel early.
func (*Machine) WhenQueue ¶ added in v0.15.0
WhenQueue waits until the passed queueTick gets processed. TODO example
func (*Machine) WhenQueueEnds ¶ added in v0.5.0
func (m *Machine) WhenQueueEnds() <-chan struct{}
WhenQueueEnds closes every time the queue ends, or the optional ctx expires.
ctx: optional context that will close the channel early.
func (*Machine) WhenTicks ¶ added in v0.5.0
WhenTicks waits N ticks of a single state (relative to now). Uses WhenTime underneath.
ctx: optional context that will close the channel early.
func (*Machine) WhenTime ¶ added in v0.5.0
WhenTime returns a channel that will be closed when all the passed states have passed the specified time. The time is a logical clock of the state. Machine time can be sourced from Machine.Time(), or Machine.Clock().
ctx: optional context that will close the channel early.
func (*Machine) WhenTime1 ¶ added in v0.11.0
WhenTime1 waits till ticks for a single state equal the given value (or more).
ctx: optional context that will close the channel early.
func (*Machine) WillBe ¶ added in v0.8.0
WillBe returns true if the passed states are scheduled to be activated. Does not cover implied states, only called ones. See Machine.IsQueued to perform more detailed queries.
position: optional position assertion
func (*Machine) WillBe1 ¶ added in v0.8.0
WillBe1 returns true if the passed state is scheduled to be activated. See IsQueued to perform more detailed queries.
func (*Machine) WillBeRemoved ¶ added in v0.8.0
WillBeRemoved returns true if the passed states are scheduled to be deactivated. Does not cover implied states, only called ones. See Machine.IsQueued to perform more detailed queries.
position: optional position assertion
type Mutation ¶
type Mutation struct {
// add, set, remove
Type MutationType
// States explicitly passed to the mutation method, as their indexes. Use
// Transition.CalledStates or IndexToStates to get the actual state names.
Called []int
// argument map passed to the mutation method (if any).
Args A
// this mutation has been triggered by an auto state
// TODO rename to IsAuto
IsAuto bool
// Source is the source event for this mutation.
Source *MutSource
// IsCheck indicates that this mutation is a check, see [Machine.CanAdd].
IsCheck bool
// QueueTickNow is the queue tick during which this mutation was scheduled.
QueueTickNow uint64
// QueueLen is the length of the queue at the time when the mutation was
// queued.
QueueLen int32
// QueueTokensLen is the amount of unexecuted queue tokens (priority queue).
// TODO impl
QueueTokensLen int32
// QueueTick is the assigned queue tick at the time when the mutation was
// queued. 0 for prepended mutations.
QueueTick uint64
// QueueToken is a unique ID, which is given to prepended mutations.
// Tokens are assigned in a series but executed in random order.
QueueToken uint64
// contains filtered or unexported fields
}
Mutation represents an atomic change (or an attempt) of machine's active states. Mutation causes a Transition.
func (*Mutation) CalledIndex ¶ added in v0.12.0
func (*Mutation) LogArgs ¶ added in v0.15.0
func (m *Mutation) LogArgs(mapper LogArgsMapperFn) string
LogArgs returns a text snippet with arguments which should be logged for this Mutation.
func (*Mutation) MapArgs ¶ added in v0.15.0
func (m *Mutation) MapArgs(mapper LogArgsMapperFn) map[string]string
MapArgs returns arguments of this Mutation which match the passed [mapper]. The returned map is never nil.
func (*Mutation) StringFromIndex ¶ added in v0.12.0
type MutationType ¶
type MutationType int
MutationType enum
const ( MutationAdd MutationType = iota MutationRemove MutationSet )
func (MutationType) String ¶
func (m MutationType) String() string
type Opts ¶
type Opts struct {
// Unique ID of this machine. Default: random ID.
Id string
// Time for a handler to execute. Default: time.Second
HandlerTimeout time.Duration
// TODO docs
HandlerDeadline time.Duration
// If true, the machine will NOT print all exceptions to stdout.
DontLogStackTrace bool
// If true, the machine will die on panics.
DontPanicToException bool
// If true, the machine will NOT prefix its logs with its ID.
DontLogId bool
// Custom relations resolver. Default: *[DefaultRelationsResolver].
Resolver RelationsResolver
// Log level of the machine. Default: [LogNothing].
LogLevel LogLevel
// Tracer for the machine. Default: nil.
Tracers []Tracer
// LogArgs matching function for the machine. Default: nil.
LogArgs LogArgsMapperFn
// Parent machine, used to inherit certain properties, e.g. tracers.
// Overrides ParentID. Default: nil.
Parent Api
// ParentID is the ID of the parent machine. Default: "".
ParentId string
// Tags is a list of tags for the machine. Default: nil.
Tags []string
// QueueLimit is the maximum number of mutations that can be queued.
// Default: 1000.
QueueLimit uint16
// DetectEval will detect Eval calls directly in handlers, which causes a
// deadlock. It works in similar way as -race flag in Go and can also be
// triggered by setting either env var: AM_DEBUG=1 or AM_DETECT_EVAL=1.
// Default: false.
DetectEval bool
HandlerBackoff time.Duration
}
Opts struct is used to configure a new Machine.
func OptsWithDebug ¶ added in v0.5.0
OptsWithDebug returns Opts with debug settings (DontPanicToException, long HandlerTimeout).
func OptsWithTracers ¶ added in v0.5.0
OptsWithTracers returns Opts with the given tracers. Tracers are inherited by submachines (via Opts.Parent) when env.AM_DEBUG is set.
type Position ¶ added in v0.15.0
type Position uint8
Position describes the item's position in a list. Used mostly for the queue in Machine.IsQueued.
type RelationsResolver ¶
type RelationsResolver interface {
// TargetStates returns the target states after parsing the relations.
TargetStates(t *Transition, calledStates, index S) S
// NewAutoMutation returns an (optional) auto mutation which is appended to
// the queue after the transition is executed. It also returns the names of
// the called states.
NewAutoMutation() (*Mutation, S)
// SortStates sorts the states in the order their handlers should be
// executed.
SortStates(states S)
// RelationsOf returns a list of relation types of the given state.
RelationsOf(fromState string) ([]Relation, error)
// RelationsBetween returns a list of relation types between the given
// states.
RelationsBetween(fromState, toState string) ([]Relation, error)
InboundRelationsOf(toState string) (S, error)
// NewSchema runs when Machine receives a new struct.
NewSchema(schema Schema, states S)
}
RelationsResolver is an interface for parsing relations between states. Not thread-safe. TODO support custom relation types and additional state properties. TODO refac Relations
type Result ¶
type Result uint64
Result enum is the result of a state Transition. Queued is a virtual value and everything >= Queued (2) represents a queue tick on which the mutation will be processed. It's useful for queued negotiations.
const ( // Executed means that the transition was executed immediately and not // canceled. Executed Result = 0 // Canceled means that the transition was canceled, by either relations or a // negotiation handler. Canceled Result = 1 // Queued means that the transition was queued for later execution. Everything // above 2 also means Queued. The following methods can be used to wait for // the results: // - Machine.When // - Machine.WhenNot // - Machine.WhenArgs // - Machine.WhenTime // - Machine.WhenTime1 // - Machine.WhenTicks // - Machine.WhenQueue // - Machine.WhenQueueEnds // See [Machine.QueueTick]. Queued Result = 2 )
type S ¶
type S []string
S (state names) is a string list of state names.
func IndexToStates ¶ added in v0.12.0
IndexToStates decodes state indexes based on the provided index.
func SAdd ¶ added in v0.7.0
SAdd concatenates multiple state lists into one, removing duplicates. Useful for merging lists of states, eg a state group with other states involved in a relation.
func StatesDiff ¶ added in v0.17.0
StatesDiff returns the states that are in states1 but not in states2.
func StatesShared ¶ added in v0.17.0
StatesShared return states present in both states1 and states2.
type Schema ¶ added in v0.10.2
Schema is a map of state names to state definitions.
func ParseSchema ¶ added in v0.12.0
func SchemaClone ¶ added in v0.18.0
SchemaClone deep clones the states struct and returns a copy.
func SchemaMerge ¶ added in v0.10.3
SchemaMerge merges multiple state structs into one, overriding the previous state definitions. No relation-level merging takes place.
type SemConfig ¶ added in v0.15.0
type SemConfig struct {
// TODO
Full bool
Steps bool
Graph bool
Can bool
Queued bool
Args bool
When bool
StateCtx bool
}
SemConfig defines a config for SemLogger.
type SemLogger ¶ added in v0.15.0
type SemLogger interface {
// AddPipeOut informs that [sourceState] has been piped out into [targetMach].
// The name of the target state is unknown.
AddPipeOut(addMut bool, sourceState, targetMach string)
// AddPipeIn informs that [targetState] has been piped into this machine from
// [sourceMach]. The name of the source state is unknown.
AddPipeIn(addMut bool, targetState, sourceMach string)
// RemovePipes removes all pipes for the passed machine ID.
RemovePipes(machId string)
// IsCan return true when the machine is logging Can* methods.
IsCan() bool
// EnableCan enables / disables logging of Can* methods.
EnableCan(enable bool)
// IsSteps return true when the machine is logging transition steps.
IsSteps() bool
// EnableSteps enables / disables logging of transition steps.
EnableSteps(enable bool)
// IsGraph returns true when the machine is logging graph structures.
IsGraph() bool
// EnableGraph enables / disables logging of graph structures.
EnableGraph(enable bool)
// EnableId enables or disables the logging of the machine's ID in log
// messages.
EnableId(val bool)
// IsId returns true when the machine is logging the machine's ID in log
// messages.
IsId() bool
// EnableQueued enables or disables the logging of queued mutations.
EnableQueued(val bool)
// IsQueued returns true when the machine is logging queued mutations.
IsQueued() bool
// EnableStateCtx enables or disables the logging of active state contexts.
EnableStateCtx(val bool)
// IsStateCtx returns true when the machine is logging active state contexts.
IsStateCtx() bool
// EnableWhen enables or disables the logging of "when" methods.
EnableWhen(val bool)
// IsWhen returns true when the machine is logging "when" methods.
IsWhen() bool
// EnableArgs enables or disables the logging known args.
EnableArgs(val bool)
// IsArgs returns true when the machine is logging known args.
IsArgs() bool
// SetLogger sets a custom logger function.
SetLogger(logger LoggerFn)
// Logger returns the current custom logger function or nil.
Logger() LoggerFn
// SetLevel sets the log level of the machine.
SetLevel(lvl LogLevel)
// Level returns the log level of the machine.
Level() LogLevel
// SetEmpty creates an empty logger that does nothing and sets the log
// level in one call. Useful when combined with am-dbg. Requires LogChanges
// log level to produce any output.
SetEmpty(lvl LogLevel)
// SetSimple takes log.Printf and sets the log level in one
// call. Useful for testing. Requires LogChanges log level to produce any
// output.
SetSimple(logf func(format string, args ...any), level LogLevel)
// SetArgsMapper accepts a function which decides which mutation arguments
// to log. See NewLogArgsMapper or create one.
SetArgsMapper(mapper LogArgsMapperFn)
// SetArgsMapperDef binds and extends the default NewLogArgsMapper and LogArgs
// with [additional] arguments to be logged.
SetArgsMapperDef(additional ...string)
// ArgsMapper returns the current log args mapper function.
ArgsMapper() LogArgsMapperFn
}
SemLogger is a semantic logger for structured events. It's consist of: - enable / enabled methods - text logger utils - setters for external semantics (eg pipes) It's WIP, and eventually it will replace (but not remove) the text logger.
type Serialized ¶ added in v0.7.0
type Serialized struct {
// ID is the ID of a state machine.
// TODO refac to Id with the new dbg telemetry protocol
ID string `json:"id" yaml:"id" toml:"id"`
// StateNames is an ordered list of state names.
StateNames S `json:"state_names" yaml:"state_names" toml:"state_names"`
// Time is the [Machine.Time] value.
Time Time `json:"time" yaml:"time" toml:"time"`
// QueueTick is a value of [Machine.QueueTick].
QueueTick uint64 `json:"queue_tick" yaml:"queue_tick" toml:"queue_tick"`
// MachineTick is a value of [Machine.MachineTick].
// nolint:lll
MachineTick uint32 `json:"machine_tick" yaml:"machine_tick" toml:"machine_tick"`
}
Serialized is a machine state serialized to a JSON/YAML/TOML compatible struct. One also needs the state Struct to re-create a state machine.
type State ¶
type State struct {
Auto bool `json:"auto,omitempty"`
Multi bool `json:"multi,omitempty"`
Require S `json:"require,omitempty"`
Add S `json:"add,omitempty"`
Remove S `json:"remove,omitempty"`
After S `json:"after,omitempty"`
Tags []string `json:"tags,omitempty"`
}
State defines a single state of a machine, its properties and relations.
func StateAdd ¶ added in v0.7.0
StateAdd adds new states to relations of the source state, without removing existing ones. Useful for adjusting shared stated to a specific machine. Only "true" values for Auto and Multi are applied from [overlay].
ssS.HandshakeDone: StateAdd(
SharedSchema[ssS.HandshakeDone],
am.State{
Require: S{ssS.ClientConnected},
Remove: S{Exception},
}),
func StateSet ¶ added in v0.7.0
StateSet replaces passed relations and properties of the source state. Only relations in the overlay state are replaced, the rest is preserved. If [overlay] has all fields `nil`, then only [auto] and [multi] get applied.
ssS.HandshakeDone: StateSet(s, false, true, State{
Remove: S{"C"},
})
type StatesBase ¶ added in v0.8.0
type StatesBase struct {
// Exception is the only built-in state and mean a global error. All errors
// have to [State.Require] the Exception state. If [Machine.PanicToErr] is
// true, Exception will receive it.
Exception string
// contains filtered or unexported fields
}
func (*StatesBase) Names ¶ added in v0.8.0
func (b *StatesBase) Names() S
func (*StatesBase) SetNames ¶ added in v0.8.0
func (b *StatesBase) SetNames(names S)
func (*StatesBase) SetStateGroups ¶ added in v0.15.0
func (b *StatesBase) SetStateGroups(groups map[string][]int, order []string)
func (*StatesBase) StateGroups ¶ added in v0.15.0
func (b *StatesBase) StateGroups() (map[string][]int, []string)
type Step ¶ added in v0.5.0
type Step struct {
Type StepType
// Only for Type == StepRelation.
RelType Relation
// marks a final handler (FooState, FooEnd)
IsFinal bool
// marks a self handler (FooFoo)
IsSelf bool
// marks an enter handler (FooState, but not FooEnd). Requires IsFinal.
IsEnter bool
// Deprecated, use GetFromState(). TODO remove
FromState string
// TODO implement
FromStateIdx int
// Deprecated, use GetToState(). TODO remove
ToState string
// TODO implement
ToStateIdx int
// Deprecated, use RelType. TODO remove
Data any
}
Step struct represents a single step within a Transition, either a relation resolving step or a handler call.
func (*Step) GetFromState ¶ added in v0.9.0
GetFromState returns the source state of a step. Optional, unless no GetToState().
func (*Step) GetToState ¶ added in v0.9.0
GetToState returns the target state of a step. Optional, unless no GetFromState().
func (*Step) StringFromIndex ¶ added in v0.12.0
type StepType ¶ added in v0.5.0
type StepType int8
StepType enum
const ( StepRelation StepType = 1 << iota StepHandler // TODO rename to StepActivate StepSet // StepRemove indicates a step where a state goes active->inactive // TODO rename to StepDeactivate StepRemove // StepRemoveNotActive indicates a step where a state goes inactive->inactive // TODO rename to StepDeactivatePassive StepRemoveNotActive // TODO refac to StepCalled StepRequested StepCancel )
TODO refac with dbg-proto-v2
type Subscriptions ¶ added in v0.15.1
type Subscriptions struct {
// Mx locks the subscription manager. TODO optimize?
Mx sync.Mutex
// contains filtered or unexported fields
}
Subscriptions is an embed responsible for binding subscriptions, managing their indexes, processing triggers, and garbage collection.
func NewSubscriptionManager ¶ added in v0.15.1
func NewSubscriptionManager( mach Api, clock Clock, is, not InternalCheckFunc, log InternalLogFunc, ) *Subscriptions
func (*Subscriptions) HasWhenArgs ¶ added in v0.15.1
func (sm *Subscriptions) HasWhenArgs() bool
func (*Subscriptions) NewStateCtx ¶ added in v0.15.1
func (sm *Subscriptions) NewStateCtx(state string) context.Context
NewStateCtx returns a new sub-context, bound to the current clock's tick of the passed state.
Context cancels when the state has been deactivated, or right away, if it isn't currently active.
State contexts are used to check state expirations and should be checked often inside goroutines.
func (*Subscriptions) ProcessStateCtx ¶ added in v0.15.1
func (sm *Subscriptions) ProcessStateCtx(deactivated S) []context.CancelFunc
ProcessStateCtx collects all deactivated state contexts, and returns theirs cancel funcs. Uses transition caches.
func (*Subscriptions) ProcessWhen ¶ added in v0.15.1
func (sm *Subscriptions) ProcessWhen(activated, deactivated S) []chan struct{}
ProcessWhen collects all the matched active state subscriptions, and returns theirs channels.
func (*Subscriptions) ProcessWhenArgs ¶ added in v0.15.1
func (sm *Subscriptions) ProcessWhenArgs(e *Event) []chan struct{}
ProcessWhenArgs collects all the args-matching subscriptions, and returns theirs channels.
func (*Subscriptions) ProcessWhenQuery ¶ added in v0.16.0
func (sm *Subscriptions) ProcessWhenQuery() []chan struct{}
func (*Subscriptions) ProcessWhenQueue ¶ added in v0.15.1
func (sm *Subscriptions) ProcessWhenQueue(queueTick uint64) []chan struct{}
func (*Subscriptions) ProcessWhenQueueEnds ¶ added in v0.15.1
func (sm *Subscriptions) ProcessWhenQueueEnds() []chan struct{}
ProcessWhenQueueEnds collects all queue-end subscriptions, and returns theirs channels.
func (*Subscriptions) ProcessWhenTime ¶ added in v0.15.1
func (sm *Subscriptions) ProcessWhenTime(before Clock) []chan struct{}
ProcessWhenTime collects all the time-based subscriptions, and returns theirs channels.
func (*Subscriptions) QueueFlush ¶ added in v0.17.0
func (sm *Subscriptions) QueueFlush()
QueueFlush means a new queue, and all the queue-related subs are expired and have to be closed.
func (*Subscriptions) SetClock ¶ added in v0.17.0
func (sm *Subscriptions) SetClock(clock Clock)
SetClock sets a longer clock from an expanded schema.
func (*Subscriptions) When ¶ added in v0.15.1
func (sm *Subscriptions) When(states S, ctx context.Context) <-chan struct{}
func (*Subscriptions) WhenArgs ¶ added in v0.15.1
func (sm *Subscriptions) WhenArgs( state string, args A, ctx context.Context, ) <-chan struct{}
WhenArgs returns a channel that will be closed when the passed state becomes active with all the passed args. Args are compared using the native '=='. It's meant to be used with async Multi states, to filter out a specific call.
ctx: optional context that will close the channel when handler loop ends.
func (*Subscriptions) WhenNot ¶ added in v0.15.1
func (sm *Subscriptions) WhenNot( states S, ctx context.Context, ) <-chan struct{}
WhenNot returns a channel that will be closed when all the passed states become inactive or the machine gets disposed.
ctx: optional context that will close the channel early.
func (*Subscriptions) WhenQuery ¶ added in v0.16.0
func (sm *Subscriptions) WhenQuery( fn func(clock Clock) bool, ctx context.Context, ) <-chan struct{}
func (*Subscriptions) WhenQueue ¶ added in v0.15.1
func (sm *Subscriptions) WhenQueue(tick Result) <-chan struct{}
WhenQueue waits until the passed queueTick gets processed.
func (*Subscriptions) WhenQueueEnds ¶ added in v0.15.1
func (sm *Subscriptions) WhenQueueEnds() <-chan struct{}
WhenQueueEnds closes every time the queue ends, or the optional ctx expires. This function assumes the queue is running, and wont close early.
ctx: optional context that will close the channel early.
func (*Subscriptions) WhenTime ¶ added in v0.15.1
func (sm *Subscriptions) WhenTime( states S, times Time, ctx context.Context, ) <-chan struct{}
WhenTime returns a channel that will be closed when all the passed states have passed the specified time. The time is a logical clock of the state. Machine time can be sourced from Machine.Time(), or Machine.Clock().
ctx: optional context that will close the channel early.
type Time ¶ added in v0.7.0
type Time []uint64
Time is machine time, an ordered list of state ticks. It's like Clock, but indexed by int, instead of string. TODO use math/big?
func IndexToTime ¶ added in v0.12.0
IndexToTime returns "virtual time" with selected states active. It's useful to use time methods on a list of states, eg the called ones.
func NewTime ¶ added in v0.17.0
NewTime returns a Time of the same len as [index] with active states marked by indexes in [activeStates].
func (Time) ActiveStates ¶ added in v0.12.0
ActiveStates returns a list of active state indexes in this machine time slice. When idxs isn't nil, only the passed indexes are considered.
func (Time) After ¶ added in v0.16.0
After returns true if at least 1 tick in time1 is after time2, optionally accepting equal values for true. Requires a deterministic states order, eg by using Machine.VerifyStates.
func (Time) Any ¶ added in v0.16.0
Any is Machine.Any but for an int-based time slice.
func (Time) Any1 ¶ added in v0.8.0
Any1 is Machine.Any1 but for an int-based time slice.
func (Time) Before ¶ added in v0.16.0
Before returns true if at least 1 tick in time1 is before time2, optionally accepting equal values for true. Requires a deterministic states order, eg by using Machine.VerifyStates.
func (Time) DiffSince ¶ added in v0.10.3
DiffSince returns the number of ticks for each state in Time since the passed machine time.
func (Time) Equal ¶ added in v0.16.0
Equal checks if time1 is equal to time2. Requires a deterministic states order, eg by using Machine.VerifyStates.
func (Time) Filter ¶ added in v0.16.0
Filter returns a subset of the Time slice for the given state indexes. It's not advised to slice an already sliced time slice.
func (Time) Is ¶ added in v0.7.0
Is is Machine.Is but for an int-based time slice.
func (Time) Is1 ¶ added in v0.7.0
Is1 is Machine.Is1 but for an int-based time slice.
func (Time) NonZeroStates ¶ added in v0.16.0
NonZeroStates returns a list of state indexes with non-zero ticks in this machine time slice.
func (Time) Not ¶ added in v0.12.0
Not is Machine.Not but for an int-based time slice.
func (Time) Not1 ¶ added in v0.12.0
Not1 is Machine.Not1 but for an int-based time slice.
func (Time) Sum ¶ added in v0.9.0
Sum returns a sum of ticks for each state in Time, or narrowed down to [idxs].
func (Time) Tick ¶ added in v0.16.0
Tick is Machine.Tick but for an int-based time slice.
type TimeIndex ¶ added in v0.12.0
TimeIndex is Time with a bound state index (list of state names). It's not suitable for storage, use Time instead. See Clock for a simpler type with ticks indexes by state names.
func NewTimeIndex ¶ added in v0.12.0
NewTimeIndex returns a TimeIndex of the same len as [index] with active states marked by indexes in [activeStates].
func (TimeIndex) ActiveStates ¶ added in v0.12.0
ActiveStates is Machine.ActiveStates but for a string-based time slice.
func (TimeIndex) Any ¶ added in v0.16.0
Any is Machine.Any but for a string-based time slice.
func (TimeIndex) Any1 ¶ added in v0.12.0
Any1 is Machine.Any1 but for a string-based time slice.
func (TimeIndex) Filter ¶ added in v0.16.0
Filter is Time.Filter but for a string-based time slice.
func (TimeIndex) Is ¶ added in v0.12.0
Is is Machine.Is but for a string-based time slice.
func (TimeIndex) Is1 ¶ added in v0.12.0
Is1 is Machine.Is1 but for a string-based time slice.
func (TimeIndex) NonZeroStates ¶ added in v0.16.0
NonZeroStates is Time.NonZeroStates but for a string-based time slice.
func (TimeIndex) Not ¶ added in v0.12.0
Not is Machine.Not but for a string-based time slice.
func (TimeIndex) Not1 ¶ added in v0.12.0
Not1 is Machine.Not1 but for a string-based time slice.
func (TimeIndex) StateName ¶ added in v0.12.0
StateName returns the name of the state at the given index.
type Tracer ¶ added in v0.5.0
type Tracer interface {
TransitionInit(transition *Transition)
TransitionStart(transition *Transition)
TransitionEnd(transition *Transition)
MutationQueued(machine Api, mutation *Mutation)
HandlerStart(transition *Transition, emitter string, handler string)
HandlerEnd(transition *Transition, emitter string, handler string)
// MachineInit is called only for machines with tracers added via
// Opts.Tracers.
MachineInit(machine Api) context.Context
MachineDispose(machID string)
NewSubmachine(parent, machine Api)
Inheritable() bool
QueueEnd(machine Api)
SchemaChange(machine Api, old Schema)
VerifyStates(machine Api)
}
Tracer is an interface for logging machine transitions and events, used by Opts.Tracers and Machine.BindTracer.
type TracerNoOp ¶ added in v0.17.0
type TracerNoOp struct{}
TracerNoOp is a no-op implementation of Tracer, used for embedding.
func (*TracerNoOp) HandlerEnd ¶ added in v0.17.0
func (t *TracerNoOp) HandlerEnd( transition *Transition, emitter string, handler string)
func (*TracerNoOp) HandlerStart ¶ added in v0.17.0
func (t *TracerNoOp) HandlerStart( transition *Transition, emitter string, handler string)
func (*TracerNoOp) Inheritable ¶ added in v0.17.0
func (t *TracerNoOp) Inheritable() bool
func (*TracerNoOp) MachineDispose ¶ added in v0.17.0
func (t *TracerNoOp) MachineDispose(machID string)
func (*TracerNoOp) MachineInit ¶ added in v0.17.0
func (t *TracerNoOp) MachineInit(machine Api) context.Context
func (*TracerNoOp) MutationQueued ¶ added in v0.17.0
func (t *TracerNoOp) MutationQueued(machine Api, mutation *Mutation)
func (*TracerNoOp) NewSubmachine ¶ added in v0.17.0
func (t *TracerNoOp) NewSubmachine(parent, machine Api)
func (*TracerNoOp) QueueEnd ¶ added in v0.17.0
func (t *TracerNoOp) QueueEnd(machine Api)
func (*TracerNoOp) SchemaChange ¶ added in v0.17.0
func (t *TracerNoOp) SchemaChange(machine Api, old Schema)
func (*TracerNoOp) TransitionEnd ¶ added in v0.17.0
func (t *TracerNoOp) TransitionEnd(transition *Transition)
func (*TracerNoOp) TransitionInit ¶ added in v0.17.0
func (t *TracerNoOp) TransitionInit(transition *Transition)
func (*TracerNoOp) TransitionStart ¶ added in v0.17.0
func (t *TracerNoOp) TransitionStart(transition *Transition)
func (*TracerNoOp) VerifyStates ¶ added in v0.17.0
func (t *TracerNoOp) VerifyStates(machine Api)
type Transition ¶
type Transition struct {
// Id is a unique identifier of the transition.
Id string
// Steps is a list of steps taken by this transition (so far).
Steps []*Step
// HasStateChanged is true if the transition has changed the state of the
// machine. TODO useful?
// HasStateChanged bool
// TimeBefore is the machine time from before the transition.
TimeBefore Time
// TimeAfter is the machine time from after the transition. If the transition
// has been canceled, this will be the same as TimeBefore. This field is the
// same as TimeBefore, until the negotiation phase finishes.
TimeAfter Time
// TargetIndexes is a list of indexes of the target states.
TargetIndexes []int
// Enters is a list of states activated in this transition.
Enters S
// Enters is a list of states deactivated in this transition.
Exits S
// Mutation call which caused this transition
Mutation *Mutation
// Machine is the parent machine of this transition.
Machine *Machine
// MachApi is a subset of Machine.
// TODO call when applicable instead of calling Machine
// TODO rename to MachApi
MachApi Api
// LogEntries are log msgs produced during the transition.
LogEntries []*LogEntry
// PreLogEntries are log msgs produced before during the transition.
PreLogEntries []*LogEntry
// QueueLen is the length of the queue after the transition.
QueueLen uint16
// InternalLogEntriesLock is used to lock the logs to be collected by Tracers.
// TODO getter?
InternalLogEntriesLock sync.Mutex
// IsCompleted returns true when the execution of the transition has been
// fully completed.
IsCompleted atomic.Bool
// IsAccepted returns true if the transition has been accepted, which can
// change during the transition's negotiation phase and while resolving
// relations.
IsAccepted atomic.Bool
// TODO true for panic and timeouts
IsBroken atomic.Bool
// TODO confirms relations resolved and negotiation ended
IsSettled atomic.Bool
// contains filtered or unexported fields
}
Transition represents processing of a single mutation within a machine.
func (*Transition) Args ¶
func (t *Transition) Args() A
Args returns the argument map passed to the mutation method (or an empty one).
func (*Transition) CalledStates ¶
func (t *Transition) CalledStates() S
CalledStates return explicitly called / requested states of the transition.
func (*Transition) CleanCache ¶ added in v0.13.0
func (t *Transition) CleanCache()
func (*Transition) ClockAfter ¶ added in v0.7.0
func (t *Transition) ClockAfter() Clock
ClockAfter return the Clock from before the transition.
func (*Transition) ClockBefore ¶ added in v0.7.0
func (t *Transition) ClockBefore() Clock
ClockBefore return the Clock from before the transition.
func (*Transition) IsAuto ¶
func (t *Transition) IsAuto() bool
IsAuto returns true if the transition was triggered by an auto state. Thus, it cant trigger any other auto state mutations.
func (*Transition) IsHealth ¶ added in v0.13.0
func (t *Transition) IsHealth() bool
IsHealth returns true if the transition was health-related (StateHealthcheck, StateHeartbeat).
func (*Transition) StatesBefore ¶
func (t *Transition) StatesBefore() S
StatesBefore is a list of states before the transition.
func (*Transition) String ¶
func (t *Transition) String() string
String representation of the transition and the steps taken so far.
func (*Transition) TargetStates ¶
func (t *Transition) TargetStates() S
TargetStates is a list of states after parsing the relations.
func (*Transition) TimeIndexAfter ¶ added in v0.15.0
func (t *Transition) TimeIndexAfter() *TimeIndex
TimeIndexAfter return TimeAfter bound to an index, for easy querying.
func (*Transition) TimeIndexBefore ¶ added in v0.18.0
func (t *Transition) TimeIndexBefore() *TimeIndex
TimeIndexBefore return TimeIndexBefore bound to an index, for easy querying.
func (*Transition) TimeIndexCalled ¶ added in v0.18.0
func (t *Transition) TimeIndexCalled() *TimeIndex
TimeIndexCalled return CalledStates bound to an index, for easy querying.
func (*Transition) TimeIndexDiff ¶ added in v0.18.0
func (t *Transition) TimeIndexDiff() (*TimeIndex, *TimeIndex)
TimeIndexDiff return 2 time indexes of added and removed states by this transition. Added include Multi states.
func (*Transition) TimeIndexTouched ¶ added in v0.18.0
func (t *Transition) TimeIndexTouched() *TimeIndex
TimeIndexTouched return all the touched states as active. Requires [SemLogger.IsSteps] to be true.
func (*Transition) Type ¶
func (t *Transition) Type() MutationType
Type returns the type of the mutation (add, remove, set).
type WhenArgsBinding ¶ added in v0.7.0
type WhenArgsBinding struct {
// contains filtered or unexported fields
}
type WhenBinding ¶ added in v0.7.0
type WhenTimeBinding ¶ added in v0.7.0
type WhenTimeBinding struct {
Ch chan struct{}
// map of matched to their index positions
// TODO optimize indexes
Index map[string]int
// number of matches so far TODO len(Index) ?
Matched int
// number of total matches needed
Total int // TODO len(Times) ?
// optional Time to match for completed from Index
Times Time
Completed StateIsActive
Ctx context.Context
}
