asyncmachine-go

module
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Dec 15, 2024 License: MIT

README

asyncmachine-go

[!NOTE] State machines communicate through states (mutations, checking and waiting).

Asyncmachine-go is an AOP Actor Model library for distributed workflows, built on top of a lightweight state machine. It has atomic transitions, RPC, logging, TUI debugger, metrics, tracing, and soon diagrams.

Use cases depend on the layer of the stack used, and range from goroutine synchronization and state synchronization to worker synchronization, bots, LLM agents, consensus algos, etc. Asyncmachine-go can precisely target a specific scenario in a non-opaque way, and bring structure to event-based systems. It takes care of most contexts, select statements, and panics.

Stack

            PubSub            
          Workers          
        RPC        
      Handlers      
    Machine API    
  Relations  
States

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.Struct{
    "Foo": {Require: am.S{"Bar"}},
    "Bar": {},
}, nil)
mach.Add1("Foo", nil)
mach.Is1("Foo") // false

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

// state ctx is a non-err ctx
ctx := client.Mach.NewStateCtx(ssC.WorkerReady)
// clock-based subscription
whenPayload := client.Mach.WhenTicks(ssC.WorkerPayload, 1, ctx)
// mutation
client.WorkerRpc.Worker.Add1(ssW.WorkRequested, Pass(&A{
    Input: 2}))
// WaitFor replaces select statements
err := amhelp.WaitForAll(ctx, time.Second,
    mach2.When1("Ready", nil),
    whenPayload)
// check cancellation
if ctx.Err() != nil {
    // state ctx expired
    return
}
// check error
if err != nil {
    // mutation
    client.Mach.AddErr(err, nil)
    return
}
// client/WorkerPayload and mach2/Ready activated

Handlers - AOP transition handlers.

func (h *Handlers) FooEnter(e *am.Event) bool {
    return true
}
func (h *Handlers) FooBar(e *am.Event) bool {
    return true
}
func (h *Handlers) FooState(e *am.Event) {
    h.foo = NewConn()
}
func (h *Handlers) FooEnd(e *am.Event) {
    h.foo.Close()
}

Schema - states of a node worker.

type WorkerStatesDef struct {
    ErrWork        string
    ErrWorkTimeout string
    ErrClient      string
    ErrSupervisor  string

    LocalRpcReady     string
    PublicRpcReady    string
    RpcReady          string
    SuperConnected    string
    ServeClient       string
    ClientConnected   string
    ClientSendPayload string
    SuperSendPayload  string

    Idle          string
    WorkRequested string
    Working       string
    WorkReady     string

    // inherit from rpc worker
    *ssrpc.WorkerStatesDef
}

All examples and benchmarks can be found in /examples.

Getting Started

/pkg/machine is a mandatory ready, while /pkg/node is the most interesting one. Examples in /examples and /docs/manual.md are good for a general grasp, while /docs/diagrams.md go deeper into implementation details. Reading tests is always a good idea.

Packages

  • /pkg/helpers Useful functions when working with async state machines.
  • /pkg/history History tracking and traversal.
  • /pkg/machine State machine, the main package. Dependency free and semver compatible.
  • /pkg/node Distributed worker pools with supervisors.
  • /pkg/rpc Remote state machines, with the same API as local ones.
  • /pkg/states Reusable state definitions and piping.
  • /pkg/telemetry Telemetry exporters for metrics, traces, and logs.
  • /pkg/pubsub Planned.
  • /tools/cmd/am-dbg Multi-client TUI debugger.
  • /tools/cmd/am-gen Generates states files and Grafana dashboards.
  • /tools/cmd/am-vis Planned.

dashboard

Case Studies

Bigger implementations worth reading:

Documentation

Community

Status

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

Development

  • all PRs welcome
  • before
    • ./scripts/dep-taskfile.sh
    • task install-deps
  • after
    • task test
    • task format
    • task lint

FAQ

How does asyncmachine work?

It calls certain methods on a struct in a certain order (eg BarEnter, FooFoo, FooBar, BarState).

What is a "state" in asyncmachine?

State as in "status", not state as in "data". For example, not a JSON string, but "process RUNNING", or "car BROKEN".

Can asyncmachine be integrated with other frameworks?

Yes, because asyncmachine is more of a set of libraries following the same conventions, than an actual framework. It can integrate with anything via states-based APIs.

How does asyncmachine compare to Temporal?

Temporal is an all-in-one solution with data persistence, which is its limitation. Asyncmachine doesn't hold any data by itself and has progressive layers, making it usable in a wide variety of use cases (e.g. asyncmachine could do workflows for a desktop app).

How does asyncmachine compare to Ergo?

Ergo is a great framework, but leans on old ideas and has web-based tooling. It also isn't natively based on state machines. Asyncmachine provides productivity-focused TUI tooling and rich integrations, while having every component natively state-based (even the code generator).

Does aRPC auto sync data?

aRPC auto syncs only states (clock values). Mutations carry data in arguments, from client to server, while the SendPayload state passes payloads back to the client.

Does asyncmachine return data?

No, just yes/no/later (Executed, Canceled, Queued).

Does asyncmachine return errors?

No, but there's an error state (Exception). Optionally, there are also detailed error states (e.g. ErrNetwork).

Why asyncmachine avoids blocking?

The lack of blocking allows for immediate adjustment to incoming changes and is backed by solid cancellation support.

What does "clock-based" mean?

Each state has a counter of activations, and all state counters create "machine time".

What's the difference between states and events?

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

How do I do X/Y/Z in asyncmachine?

Usually the answer is "make it a state".

Changes

Directories

Path Synopsis
examples
internal
testing/cmd/am-dbg-worker
AM_DBG_WORKER_ADDR AM_DBG_ADDR
AM_DBG_WORKER_ADDR AM_DBG_ADDR
pkg
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 mutation history tracking and traversal.
Package history provides mutation history tracking and traversal.
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.
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 pipe provide helpers to pipe states from one machine to another.
Package pipe provide helpers to pipe states from one machine to another.
telemetry
Package telemetry provides telemetry exporters for asyncmachine: am-dbg, Prometheus, and OpenTelemetry.
Package telemetry provides telemetry exporters for asyncmachine: am-dbg, Prometheus, and OpenTelemetry.
telemetry/prometheus
Package prometheus provides Prometheus metrics for asyncmachine.
Package prometheus provides Prometheus metrics for asyncmachine.
x/helpers
Package helpers provides some utility functions for asyncmachine, which are out of scope of the main package.
Package helpers provides some utility functions for asyncmachine, which are out of scope of the main package.
scripts
tools
cmd/am-dbg
am-dbg is a lightweight, multi-client debugger for asyncmachine-go.
am-dbg is a lightweight, multi-client debugger for asyncmachine-go.
cmd/am-dbg-ssh
am-dbg-ssh is an SSH version of asyncmachine-go debugger.
am-dbg-ssh is an SSH version of asyncmachine-go debugger.
cmd/am-gen
am-gen generates states files and Grafana dashboards.
am-gen generates states files and Grafana dashboards.
debugger
Package debugger provides a TUI debugger with multi-client support.
Package debugger provides a TUI debugger with multi-client support.

Jump to

Keyboard shortcuts

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