asyncmachine-go

module
v0.18.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 7, 2026 License: MIT

README

website

asyncmachine-go

OpenTelemetry traces in Jaeger

[!NOTE] State machines communicate through states.

asyncmachine-go is a distributed workflow engine (technically a pathless control-flow graph with a consensus), which implements AOP and actor model through a clock-based state-machine. It features atomic transitions, relations, transparent RPC, TUI debugger, telemetry, REPL, selective distribution, diagrams, and WASM support.

As a control flow library, it decides about running of predefined bits of code (transition handlers) - their order and which ones to run, according to currently active states (flags). Thanks to a novel state machine, the number of handlers can be minimized while maximizing scenario coverage. It's lightweight, fault-tolerant by design, has rule-based mutations, and can target virtually any step-in-time, in any workflow. It's a low-level tool with acceptable performance.

asyncmachine-go takes care of context, select, and panic, while allowing for graph-structured concurrency with goroutine cancelation. The history log and relations have vector formats. It aims to create autonomous workflows with organic control flow and stateful APIs.

[!NOTE] git clone https://github.com/pancsta/asyncmachine-go.git

Each state represents
  • binary flag
  • node with relations
  • AOP aspect
  • logical clock
  • subscription topic
  • multiple methods
  • metric
  • trace
  • lock
  • breakpoint

Besides the main use-case of workflows, it can be used for stateful applications of any size - daemons, UIs, configs, bots, firewalls, synchronization consensus, games, smart graphs, microservice orchestration, robots, contracts, streams, DI containers, message broking, test scenarios, simulators, as well as "real-time" systems which rely on instant cancelation.

[!NOTE] Flow is state, and state is flow, in a graph.

Samples

Minimal - an untyped definition of 2 states and 1 relation, then 1 mutation and a check.

import am "github.com/pancsta/asyncmachine-go/pkg/machine"
// ...
mach := am.New(nil, am.Schema{
    "Foo": {Require: am.S{"Bar"}},
    "Bar": {},
}, nil)
mach.Add1("Foo", nil)
mach.Is1("Foo") // false

Complicated - wait on a multi state (event) and the Ready state with a 1s timeout, then mutate with typed args, on top of a state context.

// state ctx is an expiration ctx
ctx := client.Mach.NewStateCtx(ssC.WorkerReady)
// clock-based subscription
whenPayload := client.Mach.WhenTicks(ssC.WorkerPayload, 1, ctx)
// state mutation
client.RpcWorker.NetMach.Add1(ssW.WorkRequested, Pass(&A{
    Input: 2}))
// WaitFor* wraps select statements
err := amhelp.WaitForAll(ctx, time.Second,
    // post-mutation subscription
    mach.When1(ss.BasicStatesDef.Ready, nil),
    // pre-mutation subscription
    whenPayload)
// check cancelation
if ctx.Err() != nil {
    return // state ctx expired
}
// check error
if err != nil {
    // error state mutation
    client.Mach.AddErr(err, nil)
    return // no err required
}
// client/WorkerPayload and mach/Ready activated

[!NOTE] Clock-based navigation in time.

Handlers - Aspect Oriented transition handlers.

// can Foo activate?
func (h *Handlers) FooEnter(e *am.Event) bool {
    return true
}
// with Foo active, can Bar activate?
func (h *Handlers) FooBar(e *am.Event) bool {
    return true
}
// Foo activates
func (h *Handlers) FooState(e *am.Event) {
    h.foo = NewConn()
}
// Foo de-activates
func (h *Handlers) FooEnd(e *am.Event) {
    h.foo.Close()
}

Schemas - relational schemas (aRPC server).

var ServerSchema = am.Schema{
    ssF.ClientConnected: {Require: S{ssS.RpcReady}},
    ssF.ErrDelivery:     {Require: S{ssS.Exception}},
    ssF.ErrHandlerTimeout: {
        Add:     S{ssS.Exception},
        Multi:   true,
        Require: S{ssS.Exception},
    },
    ssF.ErrNetwork: {
        Remove:  S{ssS.ClientConnected},
        Require: S{ssS.Exception},
    },
    ssF.ErrNetworkTimeout: {Require: S{ssS.Exception}},
    ssF.ErrOnClient:       {Require: S{ssS.Exception}},
    ssF.ErrProviding:      {Require: S{ssS.Exception}},
    ssF.ErrRpc:            {Require: S{ssS.Exception}},
    ssF.ErrSendPayload:    {Require: S{ssS.Exception}},
    ssF.Exception:         {Multi: true},
    ssF.HandshakeDone: {
        Remove:  S{ssS.Handshaking, ssS.HandshakeDone, ssS.Exception},
        Require: S{ssS.Start, ssS.ClientConnected},
    },
    ssF.Handshaking: {
        Remove:  S{ssS.Handshaking, ssS.HandshakeDone},
        Require: S{ssS.Start},
    },
    ssF.Healthcheck: {Multi: true},
    ssF.Heartbeat:   {},
    ssF.MetricSync:  {Multi: true},
    ssF.Ready: {
        Auto:    true,
        Require: S{ssS.HandshakeDone, ssS.RpcReady},
    },
    ssF.RpcAccepting: {
        Remove:  S{ssS.RpcStarting, ssS.RpcAccepting, ssS.RpcReady},
        Require: S{ssS.Start},
    },
    ssF.RpcReady: {
        Remove:  S{ssS.RpcStarting, ssS.RpcAccepting, ssS.RpcReady},
        Require: S{ssS.Start},
    },
    ssF.RpcStarting: {
        Remove:  S{ssS.RpcStarting, ssS.RpcAccepting, ssS.RpcReady},
        Require: S{ssS.Start},
    },
    ssF.SendPayload:     {Multi: true},
    ssF.Start:           {Add: S{ssS.RpcStarting}},
    ssF.WebSocketTunnel: {},
}

All examples and benchmarks can be found in /examples.

Getting Started

Packages

This monorepo offers the following importable packages, especially:

  • 🦾 /pkg/machine State machine, dependency free, semver compatible.
  • /pkg/states Reusable state schemas, handlers, and piping.
  • /pkg/helpers Useful functions when working with async state machines.
  • /pkg/telemetry Telemetry exporters for dbg, metrics, traces, and logs.

Other packages:

  • /pkg/rpc Remote state machines, with the same API as local ones.
  • /pkg/history History tracking and traversal, including Key-Value and SQL.
  • /pkg/integrations Integrations with NATS and JSON.
  • /pkg/graph Directional multigraph of connected state machines.
  • /pkg/node Distributed worker pools with supervisors.
  • /pkg/pubsub Decentralized PubSub based on libp2p gossipsub.

Devtools

[!NOTE] Inspecting cause-and-effect in distributed systems.

Apps

asyncmachine-go synchronizes state for the following projects:

Documentation

Goals

  • scale up, not down
  • defaults work by default
  • everything can be traced and debugged
  • automation is evolution
  • state != data

Community

OpenTelemetry traces in Jaeger

[!NOTE] Hundreds of clones.

Status

Under development, status depends on each package. The bottom layers seem prod grade, the top ones are alpha or testing.

[!NOTE] Managing distributed concurrency.

Development

  • good first issues
  • before
    • ./scripts/dep-taskfile.sh
    • task install-deps
  • after
    • task test
    • task format
    • task lint
    • task precommit
Roadmap
  • more tooling and diagrams
  • bug fixes, optimizations
  • network security, ACLs
  • ROADMAP.md

[!NOTE] Step by step.

FAQ

How does asyncmachine work?

It calls struct methods according to conventions, a schema, and currently active states (eg BarEnter, FooFoo, FooBar, BarState). It tackles nondeterminism by embracing it - like an UDP event stream with structure.

What is a "state" in asyncmachine?

State is a binary ID as in status / switch / flag, eg "process RUNNING" or "car BROKEN".

What does "clock-based" mean?

Each state has a counter of activations & deactivations, and all state counters create "machine time". These are logical clocks, and the queue is also (partially) counted.

What's the difference between states and events?

The same event happening many times will cause only 1 state activation, until the state becomes inactive.

The complete FAQ is available at FAQ.md.

Changes

TUI Debugger

[!NOTE] Don't lose your sync.

Directories

Path Synopsis
examples
arpc/client command
arpc/server command
basic command
ProcessingFile to FileProcessed 1 async and 1 sync state
ProcessingFile to FileProcessed 1 async and 1 sync state
cli command
cli/states
Package states contains a stateful schema-v2 for a CLI.
Package states contains a stateful schema-v2 for a CLI.
cli_daemon/cli command
cli_daemon/states
Package states contains a stateful schema-v2 for a CLI.
Package states contains a stateful schema-v2 for a CLI.
fan_out_in command
mach_template command
mach_template/states
Package states contains a stateful schema-v2 for MachTemplate.
Package states contains a stateful schema-v2 for MachTemplate.
pipes command
raw_strings command
Package main is an educational example of a state machine operating on string-based states.
Package main is an educational example of a state machine operating on string-based states.
repl command
subscriptions command
tui command
wasm/client command
wasm/server command
internal
testing/cmd/am-dbg-worker command
AM_DBG_WORKER_ADDR AM_DBG_ADDR
AM_DBG_WORKER_ADDR AM_DBG_ADDR
testing/libp2p-uds
Package uds was auto-translated from rust-libp2p.
Package uds was auto-translated from rust-libp2p.
pkg
graph
Package graph provides a graph or interconnected state-machines and their states, based on the dbg telemetry protocol.
Package graph provides a graph or interconnected state-machines and their states, based on the dbg telemetry protocol.
helpers
Package helpers is a set of useful functions when working with async state machines.
Package helpers is a set of useful functions when working with async state machines.
helpers/testing
Package testing provides testing helpers for state machines using testify.
Package testing provides testing helpers for state machines using testify.
history
Package history provides machine history tracking and traversal using the process' memory and structs.
Package history provides machine history tracking and traversal using the process' memory and structs.
history/bbolt
Package bbolt provides machine history tracking and traversal using the bbolt K/V database.
Package bbolt provides machine history tracking and traversal using the bbolt K/V database.
machine
Package machine is a nondeterministic, multi-state, clock-based, relational, optionally-accepting, and non-blocking state machine.
Package machine is a nondeterministic, multi-state, clock-based, relational, optionally-accepting, and non-blocking state machine.
node
Package node provides distributed worker pools with supervisors.
Package node provides distributed worker pools with supervisors.
pubsub/states
Package states contains a stateful schema-v2 for Topic.
Package states contains a stateful schema-v2 for Topic.
rpc
Package rpc is a transparent RPC for state machines.
Package rpc is a transparent RPC for state machines.
states
Package states provides reusable state definitions.
Package states provides reusable state definitions.
states/pipes
Package pipes provide helpers to pipe states from one machine to another.
Package pipes provide helpers to pipe states from one machine to another.
telemetry
Package telemetry provides telemetry exporters: am-dbg, Prometheus, OpenTelemetry.
Package telemetry provides telemetry exporters: am-dbg, Prometheus, OpenTelemetry.
telemetry/prometheus
Package prometheus provides Prometheus metrics for asyncmachine.
Package prometheus provides Prometheus metrics for asyncmachine.
x/helpers
Package helpers provides experimental and unstable helpers.
Package helpers provides experimental and unstable helpers.
tools
cmd/am-dbg command
am-dbg is a lightweight, multi-client debugger for asyncmachine-go.
am-dbg is a lightweight, multi-client debugger for asyncmachine-go.
cmd/am-gen command
am-gen generates schema files and Grafana dashboards.
am-gen generates schema files and Grafana dashboards.
cmd/am-relay command
cmd/am-vis command
Package am-vis generates diagrams of a filtered graph.
Package am-vis generates diagrams of a filtered graph.
cmd/arpc command
debugger
Package debugger provides a TUI debugger with multi-client support.
Package debugger provides a TUI debugger with multi-client support.
generator
Package generator generates state-machine schemas and grafana dashboards.
Package generator generates state-machine schemas and grafana dashboards.
relay/states
Package states contains a stateful schema-v2 for Relay.
Package states contains a stateful schema-v2 for Relay.
repl
Package repl provides a REPL and CLI functionality for aRPC connections.
Package repl provides a REPL and CLI functionality for aRPC connections.
repl/states
Package states contains a stateful schema-v2 for Repl.
Package states contains a stateful schema-v2 for Repl.
visualizer/states
Package states contains a stateful schema-v2 for Visualizer.
Package states contains a stateful schema-v2 for Visualizer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL