asyncmachine-go

module
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2024 License: MIT

README

asyncmachine-go

TUI Debugger

This is the monorepo of asyncmachine-go, a clock-based state machine for managing complex asynchronous workflows in an inspectable, safe, and structured way. It features a TUI debugger, transparent RPC, and telemetry for Otel & Prom.

asyncmachine can transform blocking APIs into controllable state machines with ease. It shares similarities with Ergo's actor model, but focuses on workflows like Temporal. Unlike both mentioned frameworks, it's lightweight (3k LoC, stdlib-only) and adds features progressively.

mach := am.New(nil, am.Struct{
    "Foo": {Requires: "Bar"},
    "Bar": {},
}, nil)
mach.Add1("Foo", nil)
mach.Is1("Foo") // false
Expand the full example
// ProcessingFile -> FileProcessed (1 async and 1 sync state)
package main

import am "github.com/pancsta/asyncmachine-go/pkg/machine"

func main() {
    // init the state machine
    mach := am.New(nil, am.Struct{
        "ProcessingFile": {
            Add: am.S{"InProgress"},
            Remove: am.S{"FileProcessed"},
        },
        "FileProcessed": {
            Remove: am.S{"ProcessingFile", "InProgress"},
        },
        "InProgress": {},
    }, nil)
    mach.BindHandlers(&Handlers{
        Filename: "README.md",
    })
    // change the state
    mach.Add1("ProcessingFile", nil)
    // wait for completed
    select {
    case <-time.After(5 * time.Second):
        println("timeout")
    case <-mach.WhenErr(nil):
        println("err:", mach.Err)
    case <-mach.When1("FileProcessed", nil):
        println("done")
    }
}

type Handlers struct {
    Filename string
}

// negotiation handler
func (h *Handlers) ProcessingFileEnter(e *am.Event) bool {
    // read-only ops
    // decide if moving fwd is ok
    // no blocking
    // lock-free critical zone
    return true
}

// final handler
func (h *Handlers) ProcessingFileState(e *am.Event) {
    // read & write ops
    // no blocking
    // lock-free critical zone
    mach := e.Machine
    // tick-based context
    stateCtx := mach.NewStateCtx("ProcessingFile")
    go func() {
        // block in the background, locks needed
        if stateCtx.Err() != nil {
            return // expired
        }
        // blocking call
        err := processFile(h.Filename, stateCtx)
        if err != nil {
            mach.AddErr(err)
            return
        }
        // re-check the tick ctx after a blocking call
        if stateCtx.Err() != nil {
            return // expired
        }
        // move to the next state in the flow
        mach.Add1("FileProcessed", nil)
    }()
}

Packages

To get started, it's recommended to read /pkg/machine first.

  • /pkg/helpers
    Useful functions when working with state machines.
  • /pkg/history
    History tracking and traversal.
  • /pkg/machine
    State machine, this package always gets shipped to production, and is semver compatible.
  • /pkg/rpc
    Clock-based remote state machines, with the same API as local ones.
  • /pkg/states
    Repository of common state definitions, so APIs can be more unifed.
  • /pkg/telemetry
    Telemetry exporters for am-dbg, Open Telemetry and Prometheus.
  • /pkg/pubsub
    Planned.
  • /pkg/x/helpers
    Not-so useful functions when working with state machines.
  • /tools/cmd/am-dbg
    am-dbg is a multi-client TUI debugger.
  • /tools/cmd/am-gen
    am-gen is useful for bootstrapping states files.

Case Studies

Documentation

Development

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

Changelog

Latest release: v0.7.0

  • docs: update readmes, manual, cookbook for v0.7 #127 (@pancsta)
  • feat: release v0.7 #126 (@pancsta)
  • refac(telemetry): switch telemetry to Tracer API #125 (@pancsta)
  • fix(machine): fix test -race #124 (@pancsta)
  • feat(machine): add Index() and Time.Is(index) #123 (@pancsta)
  • feat(machine): add Eval() detection tool #122 (@pancsta)
  • feat(machine): add EnvLogLevel #121 (@pancsta)
  • feat(rpc): add grpc benchmark #120 (@pancsta)
  • feat(machine): add PanicToErr, PanicToErrState #119 (@pancsta)
  • feat(helpers): add pkg/helpers (Add1Block, Add1AsyncBlock, ...) #118 (@pancsta)
  • feat(rpc): add pkg/rpc #117 (@pancsta)
  • feat(states): add pkg/states #116 (@pancsta)
  • feat(machine): add state def manipulations (eg StateAdd) #115 (@pancsta)
  • feat(machine): add new Tracer methods (eg VerifyStates) #114 (@pancsta)
  • feat(rpc): add rpc tests, including remote machine suite #113 (@pancsta)
  • feat(machine): add SetLoggerSimple, SetLoggerEmpty #112 (@pancsta)
  • feat(machine): add AddErrState and unified stack traces #111 (@pancsta)

Maintenance release: v0.6.5

  • fix(am-dbg): correct timeline tailing #110 (@pancsta)
  • fix(am-dbg): escape secondary logtxt brackets #109 (@pancsta)
  • fix(am-dbg): fix filtering in TailMode #108 (@pancsta)
  • fix(am-dbg): stop playing on timeline jumps #107 (@pancsta)
  • fix(am-dbg): fix changing log level removed trailing tx #106 (@pancsta)
  • fix(am-dbg): allow state jump after search as type #100 #105 (@pancsta)
  • fix(am-dbg): align tree rel lines #104 (@pancsta)
  • fix(am-dbg): fix tree highlights for ref links #103 (@pancsta)

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 state machines.
Package helpers is a set of useful functions when working with state machines.
history
Package history provides mutation history tracking and traversal.
Package history provides mutation history tracking and traversal.
machine
Package machine is a general purpose state machine for managing complex async workflows in a safe and structured way.
Package machine is a general purpose state machine for managing complex async workflows in a safe and structured way.
rpc
Package rpc is a transparent RPC for state machines.
Package rpc is a transparent RPC for state machines.
states
Package states is repository of common state definitions, used to make state-based API easier to compose and exchange.
Package states is repository of common state definitions, used to make state-based API easier to compose and exchange.
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.
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 will quickly bootstrap a typesafe states file for you.
am-gen will quickly bootstrap a typesafe states file for you.
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