Files
micro--go-micro/examples/flow-durable
wehub-resource-sync e071084ebe
govulncheck / govulncheck (push) Waiting to run
Harness (E2E) / Harnesses (mock LLM) (push) Waiting to run
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Waiting to run
Lint / golangci-lint (push) Waiting to run
Run Tests / Unit Tests (push) Waiting to run
Run Tests / Etcd Integration Tests (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 12:40:33 +08:00
..

Durable Flow

A workflow that survives a crash and resumes where it stopped.

A flow can be an ordered list of steps — a task with stages — instead of a single LLM turn. Each step is checkpointed before and after through a pluggable Checkpoint (store-backed by default), so if the process dies mid-run, the run resumes at the step it stopped on, without re-running the steps that already completed (and already had their side effects).

What this shows

A three-step checkout (reserve → charge → confirm) whose charge step fails the first time, simulating a transient outage / crash:

first run:
  reserve  → inventory reserved
  charge   → payment dependency unavailable (crash)
  run failed: payment gateway timeout

checkpoint: run 70643f61 is at step "charge" (status failed)

resume:
  charge   → payment captured
  confirm  → order confirmed

reserve ran 1 time(s) total — completed steps are not repeated on resume
no pending runs — the workflow completed durably

The key line is the last pair: on Resume, reserve does not run again — its result was checkpointed — and the run finishes.

The pieces

f := micro.NewFlow("checkout",
    micro.FlowSteps(
        micro.FlowStep{Name: "reserve", Run: reserve},
        micro.FlowStep{Name: "charge",  Run: charge},
        micro.FlowStep{Name: "confirm", Run: confirm},
    ),
    micro.FlowWithCheckpoint(micro.StoreCheckpoint(nil, "checkout")), // nil store = default; "checkout" = key scope
)

f.Execute(ctx, `{}`)        // runs; crashes at charge
pending, _ := f.Pending(ctx) // the run, checkpointed at "charge"
f.Resume(ctx, pending[0].ID) // continues from charge to the end
  • State carries a typed payload (Set/Scan) plus a Stage marker — the resume point.
  • Checkpoint persists each Run. The built-in is store-backed and keeps each flow's runs in their own store table (database flow, table checkout) via store.Scope, so one flow's runs don't share a table with another's — or with agent or service state. Point the default store at Postgres or NATS KV and a run survives a real process restart, or implement the interface to plug in Temporal, Restate, etc.
  • A real step would be flow.Call(service, endpoint) (an RPC), flow.Dispatch(agent) (hand off to an agent), or flow.LLM(prompt) (one model turn). Here they're plain funcs so durability is the only thing on display.

Run

go run main.go

No LLM key required.