Help us shape the future of Go! Take the 2026 Go Developer Survey

flow

module
v0.4.4 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2026 License: Apache-2.0

README

flow

github.com/looprig/flow is a Go library for building durable, replayable workflow engines with Pregel-style super-step execution.

It is meant for long-running business workflows where work may pause for a human, a ticket, an approval, or another external event, then resume later from a checkpoint without losing the execution frontier.

The engine itself is not an LLM or agent framework. Agents, RAG calls, tools, and subgraphs can be built as task kinds on top of the same core.

Status

Implemented and released. The engine (pkg/flow), an in-memory control plane (pkg/controlplane), a graph registry (pkg/registry) and an HTTP ingress (pkg/ingress) ship in the root module. A durable checkpoint store over the neutral storage.Ledger contract ships as the separately tagged nested module github.com/looprig/flow/store.

Known limits:

  • The only built-in CheckpointStore in the root module is the in-memory flow.MemStore, and the only ControlPlane is the in-memory controlplane.Mem. Durable checkpoints need flow/store (or your own CheckpointStore); a distributed control plane / worker dispatch adapter is not implemented.
  • pkg/ingress has no notion of run ownership or tenancy: any caller that passes the configured WithAuth authenticator may resume, get or cancel any run id. A deployment that needs tenancy must enforce it in the authenticator or a fronting proxy (see the package documentation).

Install

go get github.com/looprig/flow@latest
# optional durable checkpoint adapter (nested module, tagged store/vX.Y.Z)
go get github.com/looprig/flow/store@latest

What it is

flow lets callers define a typed graph over shared state:

  • A Task[I, O] is a reusable unit of work (flow.NewFuncTask wraps a function).
  • A vertex binds a task into a Graph[S] with a stable VertexID.
  • Selectors derive task input from graph state: S -> I.
  • Reducers fold task output back into graph state: (S, O) -> S.
  • Edges and conditional edges control what runs next.
  • Vertices in the same super-step run in parallel.
  • Checkpoints make runs durable and resumable.

Why

Most workflow engines make either graph state or task coupling hard to reason about. flow keeps the split explicit:

  • Tasks are graph-agnostic and reusable.
  • Graph wiring owns the state adapters.
  • Checkpoints store graph state and execution bookkeeping.
  • Inputs are re-derived from restored state on resume.
  • Stable IDs make execution observable and resumable across process restarts.

Core semantics

  • Execution uses Bulk Synchronous Parallel super-steps.
  • All vertices in a step read the same frozen state snapshot.
  • Reducers apply after the parallel barrier in stable VertexID order.
  • A vertex can interrupt (flow.Interrupt, flow.StatefulInterrupt), checkpoint, and return control to the caller.
  • Runner.Resume(ctx, graphRunID, payload) reloads the latest checkpoint and continues; paused vertices read the payload with flow.ResumePayload[T].
  • Runner.Cancel appends a terminal checkpoint; a cancelled run cannot resume.
  • Completed vertex work is skipped on recovery only after its checkpoint is durable.
  • Side-effecting tasks should use RunInfo.IdempotencyKey() (from flow.Info(ctx)) with external systems that support idempotency.

Packages

Package Purpose
pkg/flow The engine: Graph[S], AddVertex, Compile, Runner[S] (Run, Resume, Get, Status, Cancel), checkpoints, MemStore, hooks, typed errors, and Serve (the worker loop over a ControlPlane).
pkg/controlplane In-memory ControlPlane implementation (controlplane.Mem).
pkg/registry Concurrency-safe registry of compiled graphs (flow.RunnerHandle), keyed by (graph id, graph version), used by the worker loop and ingress.
pkg/ingress HTTP ingress: GET /v1/graphs, POST /v1/graphs/{graphID}/runs, POST /v1/runs/{id}/resume, GET /v1/runs/{id}, POST /v1/runs/{id}/cancel; ingress.Server gives secure http.Server defaults.
cmd/embed Example main: embeds the engine in-process and drives one interrupt/resume run.
cmd/service Example main: registry + in-memory control plane + flow.Serve + ingress as an HTTP service.
examples/* Runnable Example tests: graph, branch, interrupt, resume.
store/ Nested module github.com/looprig/flow/store (see below).

Usage

Adapted from examples/graph:

g := flow.NewGraph[state](graphID)

err := flow.AddVertex(g, doubleID,
    flow.NewFuncTask(func(_ context.Context, v int) (int, error) { return v * 2, nil }),
    func(s state) int { return s.Value },               // selector
    func(s *state, v int) error { s.Value = v; return nil }, // reducer
)
if err != nil {
    return err
}
// ... add finishID the same way, then wire it:
if err := g.AddEdge(doubleID, finishID); err != nil {
    return err
}

runner, err := g.Compile(doubleID, finishID) // flow.WithStore(...) for a durable store
if err != nil {
    return err
}

result, err := runner.Run(ctx, state{Value: 4})
if err != nil {
    return err
}
if result.Run.Status == flow.RunInterrupted {
    // Persist result.Run.GraphRunID and call runner.Resume later.
}

Storage and dispatch boundaries

The core module depends only on its neutral CheckpointStore and ControlPlane interfaces; its only direct Looprig dependency is github.com/looprig/core (for core/uuid). architecture_test.go fails the build if the core packages pull in storage, flow/store, NATS or a concrete store backend.

The optional github.com/looprig/flow/store nested module adapts a caller-supplied storage.Ledger; concrete local or distributed backends remain outside the core module. Distributed worker dispatch would be a separate adapter, not a package in this repository.

Where it sits

Tier 1 of the Looprig workspace: flow -> core. The nested flow/store module is tier 2 (flow/store -> flow, storage, with test-only core and fsstore) and releases on its own cadence at store/vX.Y.Z tags.

Development

The Go baseline is 1.26.8. Every Makefile target runs with GOWORK=off.

GOWORK=off go test ./...   # standalone tests
make check                 # fmt-check, vet, staticcheck, gosec, govulncheck, race tests, build
make architecture          # core-has-no-backend dependency guard

go test ./... in the root stops at the nested store/ module; run its checks from store/ (make check there as well).

Design documents live in docs/plans/:

See CONTRIBUTING.md for contribution rules.

License

Apache License 2.0. See LICENSE.

Directories

Path Synopsis
cmd
embed command
Command embed is the Tier-A example main from the flows design (§18.6): it EMBEDS the engine as a plain library — zero third-party dependencies, no service, no control plane — and drives one run end to end in-process.
Command embed is the Tier-A example main from the flows design (§18.6): it EMBEDS the engine as a plain library — zero third-party dependencies, no service, no control plane — and drives one run end to end in-process.
service command
Command service is the Tier-B example main from the flows design (§18.6): a plug-and-play HTTP service that runs the engine IN-PROCESS with still ZERO third-party dependencies.
Command service is the Tier-B example main from the flows design (§18.6): a plug-and-play HTTP service that runs the engine IN-PROCESS with still ZERO third-party dependencies.
pkg
controlplane
Package controlplane coordinates flow execution.
Package controlplane coordinates flow execution.
flow
Package flow is the durable, pregel-style workflow engine.
Package flow is the durable, pregel-style workflow engine.
ingress
Package ingress accepts inbound flow requests.
Package ingress accepts inbound flow requests.
registry
Package registry holds flow and node registrations.
Package registry holds flow and node registrations.
store module

Jump to

Keyboard shortcuts

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