go.temporal.io/server/chasm/statemachine.go
79 LOC · 21 covered · 58 uncovered · 7 ranges · 16076 concepts · 5 introducers · 7977 tests
File neighbourhood
The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.
Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.
package chasm
import (
"fmt"
"slices"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.temporal.io/api/serviceerror"
"go.temporal.io/server/common/telemetry"
)
// ErrInvalidTransition is returned from [Transition.Apply] on an invalid state transition.
var ErrInvalidTransition = serviceerror.NewFailedPrecondition("invalid transition")
// A StateMachine is anything that can get and set a comparable state S and re-generate tasks based on current state.
// It is meant to be used with [Transition] objects to safely transition their state on a given event.
type StateMachine[S comparable] interface {
StateMachineState() S
SetStateMachineState(S)
}
// Transition represents a state machine transition for a machine of type SM with state S and event E.
type Transition[S comparable, SM StateMachine[S], E any] struct {
// Source states that are valid for this transition.
Sources []S
// Destination state to transition to.
Destination S
// Function to apply the transition. Mutate the state machine object here and schedule tasks.
apply func(SM, MutableContext, E) error
}
// NewTransition creates a new [Transition] from the given source states to a destination state for a given event.
// The apply function is called after verifying the transition is possible but before setting the destination state,
// so it can inspect the current (source) state.
func NewTransition[S comparable, SM StateMachine[S], E any](src []S, dst S, apply func(SM, MutableContext, E) error) Transition[S, SM, E] {
statemachine.go ×1
return Transition[S, SM, E]{
Sources: src,
Destination: dst,
apply: apply,
}
}
// Possible returns a boolean indicating whether the transition is possible for the current state.
return slices.Contains(t.Sources, sm.StateMachineState())
}
// Apply applies a transition event to the given state machine changing the state machine's state to the transition's
// Destination on success. The apply function is called before the state is changed, so it can inspect the current
// (source) state.
func (t Transition[S, SM, E]) Apply(sm SM, ctx MutableContext, event E) (retErr error) {
statemachine.go ×2
prevState := sm.StateMachineState()
// Defer to always emit the transition telemetry event.
if telemetry.DebugMode() {
defer func() {
attrs := []attribute.KeyValue{
attribute.String("chasm.transition.source", fmt.Sprintf("%v", prevState)),
attribute.String("chasm.transition.destination", fmt.Sprintf("%v", t.Destination)),
}
if retErr != nil {
attrs = append(attrs, attribute.String("chasm.transition.error", retErr.Error()))
}
span := trace.SpanFromContext(ctx.goContext())
span.AddEvent("chasm.transition", trace.WithAttributes(attrs...))
}()
}
}
return err
}
return nil
}