|
1 | 1 | # Workflow |
2 | 2 |
|
3 | | -A Go library for defining and executing multi-step processes as |
4 | | -directed graphs. Conditional branching, parallel execution, |
5 | | -expression-driven templating, durable checkpointing, and |
6 | | -suspend/resume on signals or wall-clock waits. |
| 3 | +A Go library for defining and running multi-step processes as |
| 4 | +directed graphs. You get conditional branching, parallel execution, |
| 5 | +expression-driven templates, durable checkpointing, and the ability |
| 6 | +to suspend and resume on signals or wall-clock waits. |
7 | 7 |
|
8 | 8 | Think of it like a lightweight hybrid of Temporal and AWS Step |
9 | | -Functions, with everything that doesn't belong inside an execution |
10 | | -engine pushed out to interfaces consumers implement. |
| 9 | +Functions. The execution engine is all that lives inside; everything |
| 10 | +that doesn't belong inside an engine — storage, queues, leasing — is |
| 11 | +an interface you implement however you like. |
11 | 12 |
|
12 | 13 | Edge conditions and `${...}` parameter templates are evaluated by |
13 | 14 | [`github.com/deepnoodle-ai/expr`](https://github.com/deepnoodle-ai/expr), |
14 | 15 | a small zero-dependency expression evaluator with a Go-like syntax. |
15 | | -It is the only external dependency of the root module. |
| 16 | +It's the only external dependency of the root module. |
16 | 17 |
|
17 | 18 | ## Main concepts |
18 | 19 |
|
19 | | -| Concept | Description | |
20 | | -| -------------- | -------------------------------------------------------------------------------------- | |
21 | | -| **Workflow** | A repeatable process defined as a directed graph of steps | |
22 | | -| **Step** | A node in the graph — runs an activity, joins branches, sleeps, waits, or pauses | |
23 | | -| **Activity** | A function that performs the actual work | |
24 | | -| **Edge** | Defines flow between steps, optionally guarded by a condition | |
25 | | -| **Execution** | A single run of a workflow, with its own state | |
26 | | -| **Branch** | An independent execution thread with its own copy of state | |
27 | | -| **State** | Branch-local mutable variables that activities read and write | |
28 | | -| **Runner** | Production entry point that composes heartbeat, timeout, resume, and completion hooks | |
| 20 | +| Concept | Description | |
| 21 | +| ------------- | --------------------------------------------------------------------------------- | |
| 22 | +| **Workflow** | A repeatable process defined as a directed graph of steps | |
| 23 | +| **Step** | A node in the graph — runs an activity, joins branches, sleeps, waits, or pauses | |
| 24 | +| **Activity** | A function that performs the actual work | |
| 25 | +| **Edge** | Defines flow between steps, optionally guarded by a condition | |
| 26 | +| **Execution** | A single run of a workflow, with its own state | |
| 27 | +| **Branch** | An independent execution thread with its own copy of state | |
| 28 | +| **State** | Branch-local mutable variables that activities read and write | |
| 29 | +| **Runner** | Convenience entry point that composes heartbeat, timeout, resume, and hooks | |
29 | 30 |
|
30 | 31 | ## Quick example |
31 | 32 |
|
@@ -104,46 +105,57 @@ func main() { |
104 | 105 | } |
105 | 106 | ``` |
106 | 107 |
|
107 | | -The `Runner` is the recommended entry point for production code. It |
108 | | -composes heartbeating, default timeouts, resume-from-checkpoint, and |
109 | | -completion hooks. For one-shot scripts and tests, calling |
110 | | -`exec.Execute(ctx)` directly is fine. |
111 | | - |
112 | | -## Going to production |
113 | | - |
114 | | -The library is a pure execution engine. Storage, scheduling, signal |
115 | | -delivery, and worker leasing are the consumer's responsibility — the |
116 | | -library defines interfaces (`Checkpointer`, `StepProgressStore`, |
117 | | -`ActivityLogger`, `SignalStore`, `WorkflowRegistry`) and you wire |
118 | | -your own backends. The bundled `MemoryCheckpointer` and |
119 | | -`FileCheckpointer` are for development only. |
120 | | - |
121 | | -See [`docs/production_checklist.md`](docs/production_checklist.md) |
122 | | -for the full punch list, and [`docs/suspension.md`](docs/suspension.md) |
123 | | -for the suspend / resume / replay-safety contract. |
124 | | - |
125 | | -For a turnkey queue-backed runner and persistence backends, see |
126 | | -[`docs/worker.md`](docs/worker.md) and |
127 | | -[`docs/postgres.md`](docs/postgres.md). The |
128 | | -[`experimental/worker/`](experimental/worker/), |
129 | | -[`experimental/store/postgres/`](experimental/store/postgres/), and |
130 | | -[`experimental/store/sqlite/`](experimental/store/sqlite/) |
131 | | -submodules ship with this repo but live in their own Go modules so |
132 | | -the root module stays stdlib-only. Everything under `experimental/` |
133 | | -is functional but the API is not yet stable. |
134 | | - |
135 | | -## Reference |
136 | | - |
137 | | -- [`documentation/`](documentation/) — user guides covering |
138 | | - activities, branching, checkpointing, expressions, signals/sleep/pause, |
139 | | - state management, testing, and more. |
140 | | -- [`llms.txt`](llms.txt) — full API reference, including the JSON |
| 108 | +For one-shot scripts and tests, calling `exec.Execute(ctx)` directly |
| 109 | +is perfectly fine. The `Runner` is the convenient wrapper when you |
| 110 | +also want heartbeating, default timeouts, resume-from-checkpoint, and |
| 111 | +completion hooks. |
| 112 | + |
| 113 | +## Bring your own storage |
| 114 | + |
| 115 | +The library is a pure execution engine — it doesn't ship a database, |
| 116 | +a queue, or a UI, and it never will. Instead it defines small |
| 117 | +interfaces (`Checkpointer`, `StepProgressStore`, `ActivityLogger`, |
| 118 | +`SignalStore`, `WorkflowRegistry`) and you wire up whatever backends |
| 119 | +fit your stack. The bundled `MemoryCheckpointer` and |
| 120 | +`FileCheckpointer` are great for development and tests. |
| 121 | + |
| 122 | +If you'd rather not start from scratch, the `experimental/` |
| 123 | +submodules give you a head start: |
| 124 | + |
| 125 | +- [`experimental/worker/`](experimental/worker/) — a queue-backed |
| 126 | + durable worker with claim loop, heartbeat, reaper, and credit |
| 127 | + reconciliation. Handlers receive a `*HandlerContext` carrying the |
| 128 | + current `Claim` plus pre-fenced stores. The |
| 129 | + [`runquery`](experimental/worker/runquery/) subpackage exposes a |
| 130 | + backend-neutral read API (`GetRun`, `ListRuns`, `CountRuns`, |
| 131 | + `DeleteRun`) so dashboards can stay storage-agnostic. |
| 132 | +- [`experimental/store/postgres/`](experimental/store/postgres/) — |
| 133 | + pgx-backed persistence that implements every store interface plus |
| 134 | + `runquery.Store`. Schema namespace is configurable via |
| 135 | + `WithSchema(...)` so it can live alongside other tables. |
| 136 | +- [`experimental/store/sqlite/`](experimental/store/sqlite/) — the |
| 137 | + same surface backed by `database/sql`. Single-writer, perfect for |
| 138 | + dev and single-process deployments. |
| 139 | + |
| 140 | +These submodules have their own `go.mod`, so the root module stays |
| 141 | +stdlib-only. Their APIs are still being shaped — expect some churn. |
| 142 | + |
| 143 | +## Where to look next |
| 144 | + |
| 145 | +- [`documentation/`](documentation/) — friendly user guides for |
| 146 | + activities, branching, checkpointing, expressions, signals, sleep, |
| 147 | + pause, state management, testing, and more. |
| 148 | +- [`llms.txt`](llms.txt) — the full API reference, including the JSON |
141 | 149 | workflow format and the script-compiler interface. |
| 150 | +- [`docs/worker.md`](docs/worker.md) and |
| 151 | + [`docs/postgres.md`](docs/postgres.md) — guides for the experimental |
| 152 | + worker and Postgres store. |
| 153 | +- [`docs/suspension.md`](docs/suspension.md) — the suspend / resume / |
| 154 | + replay-safety contract. |
142 | 155 | - [`MIGRATION.md`](MIGRATION.md) — every breaking change between |
143 | 156 | pre-v1 and v1, with before/after snippets. |
144 | 157 | - [`examples/`](examples/) — runnable example programs covering |
145 | | - branching, joins, retries, child workflows, and more. See |
146 | | - [`examples/signal_wait/`](examples/signal_wait), |
147 | | - [`examples/durable_sleep/`](examples/durable_sleep), and |
148 | | - [`examples/pause_unpause/`](examples/pause_unpause) for the |
149 | | - suspend/resume primitives. |
| 158 | + branching, joins, retries, child workflows, and the suspend/resume |
| 159 | + primitives ([`signal_wait`](examples/signal_wait), |
| 160 | + [`durable_sleep`](examples/durable_sleep), |
| 161 | + [`pause_unpause`](examples/pause_unpause)). |
0 commit comments