openworkflow 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -346
- package/dist/backend.js +0 -1
- package/dist/bin/openworkflow.js +0 -1
- package/dist/client.js +0 -1
- package/dist/core/duration.js +0 -1
- package/dist/core/error.js +0 -1
- package/dist/core/json.js +0 -1
- package/dist/core/result.js +0 -1
- package/dist/core/retry.js +0 -1
- package/dist/core/schema.js +0 -1
- package/dist/core/step.js +0 -1
- package/dist/core/workflow.js +0 -1
- package/dist/execution.js +0 -1
- package/dist/index.js +0 -1
- package/dist/internal.d.ts +3 -5
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +0 -4
- package/dist/{pg → postgres}/backend.d.ts +3 -1
- package/dist/postgres/backend.d.ts.map +1 -0
- package/dist/{pg → postgres}/backend.js +5 -5
- package/dist/postgres/postgres.d.ts.map +1 -0
- package/dist/{backend-postgres → postgres}/postgres.js +0 -1
- package/dist/postgres/scripts/db-migrate.d.ts.map +1 -0
- package/dist/{pg → postgres}/scripts/db-migrate.js +0 -1
- package/dist/postgres/scripts/db-reset.d.ts.map +1 -0
- package/dist/{pg → postgres}/scripts/db-reset.js +0 -1
- package/dist/{pg → postgres}/scripts/squawk.d.ts.map +1 -1
- package/dist/{pg → postgres}/scripts/squawk.js +0 -1
- package/dist/postgres.d.ts +2 -0
- package/dist/postgres.d.ts.map +1 -0
- package/dist/postgres.js +1 -0
- package/dist/registry.js +0 -1
- package/dist/sqlite/backend.d.ts +3 -1
- package/dist/sqlite/backend.d.ts.map +1 -1
- package/dist/sqlite/backend.js +5 -5
- package/dist/sqlite/sqlite.js +0 -1
- package/dist/sqlite.d.ts +2 -0
- package/dist/sqlite.d.ts.map +1 -0
- package/dist/sqlite.js +1 -0
- package/dist/worker.js +0 -1
- package/dist/workflow.js +0 -1
- package/package.json +24 -6
- package/dist/backend-postgres/index.d.ts +0 -44
- package/dist/backend-postgres/index.d.ts.map +0 -1
- package/dist/backend-postgres/index.js +0 -535
- package/dist/backend-postgres/index.js.map +0 -1
- package/dist/backend-postgres/postgres.d.ts.map +0 -1
- package/dist/backend-postgres/postgres.js.map +0 -1
- package/dist/backend-sqlite/index.d.ts +0 -42
- package/dist/backend-sqlite/index.d.ts.map +0 -1
- package/dist/backend-sqlite/index.js +0 -655
- package/dist/backend-sqlite/index.js.map +0 -1
- package/dist/backend-sqlite/sqlite.d.ts +0 -61
- package/dist/backend-sqlite/sqlite.d.ts.map +0 -1
- package/dist/backend-sqlite/sqlite.js +0 -247
- package/dist/backend-sqlite/sqlite.js.map +0 -1
- package/dist/backend.js.map +0 -1
- package/dist/bin/openworkflow.js.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/config.d.ts +0 -34
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -49
- package/dist/config.js.map +0 -1
- package/dist/core/duration.js.map +0 -1
- package/dist/core/error.js.map +0 -1
- package/dist/core/json.js.map +0 -1
- package/dist/core/result.js.map +0 -1
- package/dist/core/retry.js.map +0 -1
- package/dist/core/schema.js.map +0 -1
- package/dist/core/step.js.map +0 -1
- package/dist/core/workflow.js.map +0 -1
- package/dist/execution.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal.js.map +0 -1
- package/dist/pg/backend.d.ts.map +0 -1
- package/dist/pg/backend.js.map +0 -1
- package/dist/pg/index.d.ts +0 -3
- package/dist/pg/index.d.ts.map +0 -1
- package/dist/pg/index.js +0 -3
- package/dist/pg/index.js.map +0 -1
- package/dist/pg/postgres.d.ts +0 -42
- package/dist/pg/postgres.d.ts.map +0 -1
- package/dist/pg/postgres.js +0 -234
- package/dist/pg/postgres.js.map +0 -1
- package/dist/pg/scripts/db-migrate.d.ts.map +0 -1
- package/dist/pg/scripts/db-migrate.js.map +0 -1
- package/dist/pg/scripts/db-reset.d.ts.map +0 -1
- package/dist/pg/scripts/db-reset.js.map +0 -1
- package/dist/pg/scripts/squawk.js.map +0 -1
- package/dist/pg/vitest.global-setup.d.ts +0 -3
- package/dist/pg/vitest.global-setup.d.ts.map +0 -1
- package/dist/pg/vitest.global-setup.js +0 -8
- package/dist/pg/vitest.global-setup.js.map +0 -1
- package/dist/registry.js.map +0 -1
- package/dist/sqlite/backend.js.map +0 -1
- package/dist/sqlite/index.d.ts +0 -3
- package/dist/sqlite/index.d.ts.map +0 -1
- package/dist/sqlite/index.js +0 -3
- package/dist/sqlite/index.js.map +0 -1
- package/dist/sqlite/sqlite.js.map +0 -1
- package/dist/testing/backend.testsuite.d.ts +0 -20
- package/dist/testing/backend.testsuite.d.ts.map +0 -1
- package/dist/testing/backend.testsuite.js +0 -1091
- package/dist/testing/backend.testsuite.js.map +0 -1
- package/dist/testing/index.d.ts +0 -2
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js +0 -2
- package/dist/testing/index.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/worker.js.map +0 -1
- package/dist/workflow.js.map +0 -1
- /package/dist/{backend-postgres → postgres}/postgres.d.ts +0 -0
- /package/dist/{pg → postgres}/scripts/db-migrate.d.ts +0 -0
- /package/dist/{pg → postgres}/scripts/db-reset.d.ts +0 -0
- /package/dist/{pg → postgres}/scripts/squawk.d.ts +0 -0
package/README.md
CHANGED
|
@@ -8,16 +8,12 @@ OpenWorkflow is a TypeScript framework for building durable, resumable workflows
|
|
|
8
8
|
that can pause for seconds or months, survive crashes and deploys, and resume
|
|
9
9
|
exactly where they left off - all without extra servers to manage.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+

|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
-
import {
|
|
15
|
-
import { OpenWorkflow } from "openworkflow";
|
|
14
|
+
import { defineWorkflow } from "openworkflow";
|
|
16
15
|
|
|
17
|
-
const
|
|
18
|
-
const ow = new OpenWorkflow({ backend });
|
|
19
|
-
|
|
20
|
-
const sendWelcomeEmail = ow.defineWorkflow(
|
|
16
|
+
export const sendWelcomeEmail = defineWorkflow(
|
|
21
17
|
{ name: "send-welcome-email" },
|
|
22
18
|
async ({ input, step }) => {
|
|
23
19
|
const user = await step.run({ name: "fetch-user" }, async () => {
|
|
@@ -43,363 +39,62 @@ const sendWelcomeEmail = ow.defineWorkflow(
|
|
|
43
39
|
);
|
|
44
40
|
```
|
|
45
41
|
|
|
46
|
-
> OpenWorkflow is in active development and moving quickly. Check out the
|
|
47
|
-
> [Roadmap](#roadmap) for what’s coming next.
|
|
48
|
-
|
|
49
42
|
## Quick Start
|
|
50
43
|
|
|
51
|
-
Prerequisites
|
|
52
|
-
|
|
53
|
-
- Node.js
|
|
54
|
-
- PostgreSQL (and/or SQLite)
|
|
55
|
-
|
|
56
|
-
### 1. Install
|
|
44
|
+
**Prerequisites:** Node.js & PostgreSQL (or SQLite)
|
|
57
45
|
|
|
58
|
-
Install
|
|
46
|
+
### Install
|
|
59
47
|
|
|
60
48
|
```bash
|
|
61
49
|
npx @openworkflow/cli init
|
|
62
50
|
```
|
|
63
51
|
|
|
64
|
-
The CLI will
|
|
65
|
-
|
|
66
|
-
and a `worker` script.
|
|
67
|
-
|
|
68
|
-
### 2. Start a worker
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
npm run worker
|
|
72
|
-
# or
|
|
73
|
-
npx @openworkflow/cli worker start
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
This runs the worker using `openworkflow.config.ts` and auto-loads workflows
|
|
77
|
-
from the configured directories (default: `openworkflow/`).
|
|
78
|
-
|
|
79
|
-
### 3. Run workflows from your app
|
|
80
|
-
|
|
81
|
-
Edit the generated workflow file and run it from your application code using the
|
|
82
|
-
OpenWorkflow client APIs (see examples below).
|
|
83
|
-
|
|
84
|
-
That's it. Your workflow is now durable, resumable, and fault-tolerant.
|
|
85
|
-
|
|
86
|
-
## Core Concepts
|
|
87
|
-
|
|
88
|
-
### Workflows
|
|
89
|
-
|
|
90
|
-
Workflows are durable functions. They can contain multiple steps, make external
|
|
91
|
-
API calls, query databases, and perform complex logic. If a workflow is
|
|
92
|
-
interrupted (crash, deploy, server restart), it resumes from its last completed
|
|
93
|
-
step.
|
|
94
|
-
|
|
95
|
-
```ts
|
|
96
|
-
const workflow = ow.defineWorkflow(
|
|
97
|
-
{ name: "my-workflow" },
|
|
98
|
-
async ({ input, step }) => {
|
|
99
|
-
// Your workflow logic here
|
|
100
|
-
return result;
|
|
101
|
-
},
|
|
102
|
-
);
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Steps
|
|
106
|
-
|
|
107
|
-
Steps are the building blocks of workflows. Each step is executed exactly once
|
|
108
|
-
and its result is memoized. Steps let you break workflows into checkpoints.
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
const result = await step.run({ name: "step-name" }, async () => {
|
|
112
|
-
// This function runs once. If the workflow restarts,
|
|
113
|
-
// this returns the cached result instead of re-running.
|
|
114
|
-
return await someAsyncWork();
|
|
115
|
-
});
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
**Why steps matter**: Imagine a workflow that charges a credit card, then sends
|
|
119
|
-
an email. Without steps, if your server crashes after charging the card, the
|
|
120
|
-
workflow would retry from the beginning and charge the customer twice. With
|
|
121
|
-
steps, the charge is memoized. The retry skips it and goes straight to sending
|
|
122
|
-
the email.
|
|
123
|
-
|
|
124
|
-
### Workers
|
|
125
|
-
|
|
126
|
-
Workers are long-running processes that poll your database for pending workflows
|
|
127
|
-
and execute them. Run workers via the CLI so workflow discovery stays in sync
|
|
128
|
-
with your `openworkflow.config.ts`:
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
npm run worker
|
|
132
|
-
# or
|
|
133
|
-
npx @openworkflow/cli worker start
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
Or, for more control, you can write your own workers:
|
|
137
|
-
|
|
138
|
-
```ts
|
|
139
|
-
import { BackendSqlite } from "@openworkflow/backend-sqlite";
|
|
140
|
-
import { OpenWorkflow } from "openworkflow";
|
|
141
|
-
|
|
142
|
-
const backend = BackendSqlite.connect("openworkflow/backend.db");
|
|
143
|
-
const ow = new OpenWorkflow({ backend });
|
|
144
|
-
|
|
145
|
-
const worker = ow.newWorker({ concurrency: 20 });
|
|
146
|
-
await worker.start();
|
|
147
|
-
|
|
148
|
-
// & to shut down...
|
|
149
|
-
await worker.stop(); // waits for in-flight workflows to complete
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Workers are stateless. They can be started, stopped, and deployed independently.
|
|
153
|
-
Your database is the source of truth.
|
|
154
|
-
|
|
155
|
-
### How it Works
|
|
156
|
-
|
|
157
|
-
1. **Your app starts a workflow**: A row is inserted into the `workflow_runs`
|
|
158
|
-
table with status `pending`.
|
|
159
|
-
2. **A worker picks it up**: The worker polls the database, claims the workflow,
|
|
160
|
-
and sets its status to `running`.
|
|
161
|
-
3. **The worker executes steps**: Each step is recorded in the `step_attempts`
|
|
162
|
-
table. If a step succeeds, its result is cached.
|
|
163
|
-
4. **The workflow completes**: The worker updates the `workflow_run` status to
|
|
164
|
-
`completed` or `failed`.
|
|
165
|
-
5. **If the worker crashes**: The workflow becomes visible to other workers via
|
|
166
|
-
a heartbeat timeout. Another worker picks it up, loads the cached step
|
|
167
|
-
results, and resumes from the next step.
|
|
168
|
-
|
|
169
|
-
## Advanced Patterns
|
|
170
|
-
|
|
171
|
-
### Parallel Steps
|
|
172
|
-
|
|
173
|
-
Run multiple steps concurrently using `Promise.all`:
|
|
174
|
-
|
|
175
|
-
```ts
|
|
176
|
-
const [user, subscription, settings] = await Promise.all([
|
|
177
|
-
step.run({ name: "fetch-user" }, async () => {
|
|
178
|
-
await db.users.findOne({ id: input.userId });
|
|
179
|
-
}),
|
|
180
|
-
step.run({ name: "fetch-subscription" }, async () => {
|
|
181
|
-
await stripe.subscriptions.retrieve(input.subId);
|
|
182
|
-
}),
|
|
183
|
-
step.run({ name: "fetch-settings" }, async () => {
|
|
184
|
-
await db.settings.findOne({ userId: input.userId });
|
|
185
|
-
}),
|
|
186
|
-
]);
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
Each step is still memoized individually. If the workflow crashes mid-execution,
|
|
190
|
-
completed steps return instantly on resume.
|
|
191
|
-
|
|
192
|
-
### Automatic Retries
|
|
193
|
-
|
|
194
|
-
Steps can retry automatically with exponential backoff:
|
|
195
|
-
|
|
196
|
-
```ts
|
|
197
|
-
const data = await step.run({ name: "fetch-external-api" }, async () => {
|
|
198
|
-
// If this throws, the step retries automatically
|
|
199
|
-
return await externalAPI.getData();
|
|
200
|
-
});
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
Configure retry behavior at the workflow or step level (coming soon) or handle
|
|
204
|
-
errors explicitly in your step functions.
|
|
205
|
-
|
|
206
|
-
### Sleeping (Pausing) Workflows
|
|
207
|
-
|
|
208
|
-
You can pause a workflow until a future time and, because sleeping releases the
|
|
209
|
-
worker slot, you can pause thousands of workflows without tying up compute:
|
|
210
|
-
|
|
211
|
-
```ts
|
|
212
|
-
// Pause for 1 hour (durable, non-blocking)
|
|
213
|
-
await step.sleep("wait-one-hour", "1h");
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
The sleep step is memoized after it completes. If the workflow is replayed again
|
|
217
|
-
(e.g. due to a later retry) the completed sleep is not re-applied.
|
|
218
|
-
|
|
219
|
-
#### Duration Formats
|
|
220
|
-
|
|
221
|
-
Durations accept a number followed by a unit:
|
|
222
|
-
|
|
223
|
-
| Unit | Aliases | Examples |
|
|
224
|
-
| ------------ | --------------------- | ---------------- |
|
|
225
|
-
| milliseconds | `ms`, `msec`, `msecs` | `100ms`, `1.5ms` |
|
|
226
|
-
| seconds | `s`, `sec`, `secs` | `5s`, `0.25s` |
|
|
227
|
-
| minutes | `m`, `min`, `mins` | `2m`, `1.5m` |
|
|
228
|
-
| hours | `h`, `hr`, `hrs` | `1h`, `0.25h` |
|
|
229
|
-
| days | `d`, `day(s)` | `1d`, `0.5d` |
|
|
230
|
-
| weeks | `w`, `week(s)` | `1w`, `2w` |
|
|
231
|
-
| months | `mo`, `month(s)` | `1mo`, `2mo` |
|
|
232
|
-
| years | `y`, `yr`, `yrs` | `1y`, `2yr` |
|
|
233
|
-
|
|
234
|
-
See more examples of accepted duration formats and aliases in the
|
|
235
|
-
[tests](https://github.com/openworkflowdev/openworkflow/blob/main/packages/openworkflow/core/duration.test.ts).
|
|
236
|
-
|
|
237
|
-
### Type Safety
|
|
238
|
-
|
|
239
|
-
Workflows are fully typed. Define input and output types for compile-time
|
|
240
|
-
safety:
|
|
241
|
-
|
|
242
|
-
```ts
|
|
243
|
-
interface ProcessOrderInput {
|
|
244
|
-
orderId: string;
|
|
245
|
-
userId: string;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
interface ProcessOrderOutput {
|
|
249
|
-
paymentId: string;
|
|
250
|
-
shipmentId: string;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const processOrder = ow.defineWorkflow<ProcessOrderInput, ProcessOrderOutput>(
|
|
254
|
-
{ name: "process-order" },
|
|
255
|
-
async ({ input, step }) => {
|
|
256
|
-
// input is typed as ProcessOrderInput
|
|
257
|
-
// return type must match ProcessOrderOutput
|
|
258
|
-
return { paymentId: "...", shipmentId: "..." };
|
|
259
|
-
},
|
|
260
|
-
);
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Waiting for Results
|
|
264
|
-
|
|
265
|
-
You can wait for a workflow to complete and get its result:
|
|
266
|
-
|
|
267
|
-
```ts
|
|
268
|
-
const run = await myWorkflow.run({ data: "..." });
|
|
269
|
-
|
|
270
|
-
// Wait for the workflow to finish (polls the database)
|
|
271
|
-
const result = await run.result();
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Canceling Workflows
|
|
275
|
-
|
|
276
|
-
You can cancel a workflow that is pending, running, or sleeping to prevent a
|
|
277
|
-
workflow from continuing on to the next step:
|
|
278
|
-
|
|
279
|
-
```ts
|
|
280
|
-
const handle = await myWorkflow.run({ data: "..." });
|
|
281
|
-
|
|
282
|
-
// Cancel the workflow
|
|
283
|
-
await handle.cancel();
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
### Workflow Versioning
|
|
287
|
-
|
|
288
|
-
When you need to change workflow logic, use versioning for backwards
|
|
289
|
-
compatibility.
|
|
290
|
-
|
|
291
|
-
Define a workflow with an optional version:
|
|
292
|
-
|
|
293
|
-
```ts
|
|
294
|
-
const workflow = ow.defineWorkflow(
|
|
295
|
-
{ name: "my-workflow", version: "v2" },
|
|
296
|
-
async ({ input, step, version }) => {
|
|
297
|
-
if (version === "v2") {
|
|
298
|
-
// v2 runs go here
|
|
299
|
-
await step.run({ name: "new-step" }, async () => {
|
|
300
|
-
// legacy logic
|
|
301
|
-
});
|
|
302
|
-
} else {
|
|
303
|
-
// v1 runs go here
|
|
304
|
-
await step.run({ name: "old-step" }, async () => {
|
|
305
|
-
// ...
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
},
|
|
309
|
-
);
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### Validating Workflow Inputs
|
|
313
|
-
|
|
314
|
-
You can require `.run()` callers to provide specific inputs by supplying a
|
|
315
|
-
`schema` when defining the workflow. The schema is evaluated before the run is
|
|
316
|
-
enqueued, so invalid requests fail immediately.
|
|
317
|
-
|
|
318
|
-
```ts
|
|
319
|
-
import { z } from "zod";
|
|
320
|
-
|
|
321
|
-
const summarizeDoc = ow.defineWorkflow(
|
|
322
|
-
{
|
|
323
|
-
name: "summarize",
|
|
324
|
-
schema: z.object({
|
|
325
|
-
docUrl: z.string().url(),
|
|
326
|
-
}),
|
|
327
|
-
},
|
|
328
|
-
async ({ input, step }) => {
|
|
329
|
-
// `input` has type { docUrl: string }
|
|
330
|
-
},
|
|
331
|
-
);
|
|
332
|
-
|
|
333
|
-
// Throws before enqueueing the workflow because the input isn't a URL
|
|
334
|
-
await summarizeDoc.run({ docUrl: "not-a-url" });
|
|
335
|
-
```
|
|
52
|
+
The CLI will guide you through setup and generate everything you need to get
|
|
53
|
+
started.
|
|
336
54
|
|
|
337
|
-
|
|
338
|
-
custom logic or lightweight checks). Libraries such as Zod, ArkType, Valibot,
|
|
339
|
-
and Yup.
|
|
55
|
+
For more details, check out our [docs](https://openworkflow.dev/docs).
|
|
340
56
|
|
|
341
|
-
##
|
|
57
|
+
## Features
|
|
342
58
|
|
|
343
|
-
- **
|
|
344
|
-
- **
|
|
345
|
-
- **
|
|
346
|
-
|
|
347
|
-
- **
|
|
348
|
-
- **
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
});
|
|
354
|
-
```
|
|
355
|
-
- **Namespaces** (optional): Use `namespaceId` in your backend configuration to
|
|
356
|
-
isolate workflows per environment:
|
|
357
|
-
```ts
|
|
358
|
-
const backend = await BackendPostgres.connect(postgresUrl, {
|
|
359
|
-
namespaceId: "production",
|
|
360
|
-
});
|
|
361
|
-
```
|
|
59
|
+
- ✅ **Durable** - Workflows survive crashes and deploys
|
|
60
|
+
- ✅ **Resumable** - Pick up exactly where you left off
|
|
61
|
+
- ✅ **Type-safe** - Full TypeScript support
|
|
62
|
+
- ✅ **Step memoization** - Never repeat completed work
|
|
63
|
+
- ✅ **Automatic retries** - Built-in exponential backoff
|
|
64
|
+
- ✅ **Long pauses** - Sleep for seconds or months
|
|
65
|
+
- ✅ **Parallel execution** - Run steps concurrently
|
|
66
|
+
- ✅ **No extra servers** - Uses your existing database
|
|
67
|
+
- ✅ **Dashboard included** - Monitor and debug workflows
|
|
68
|
+
- ✅ **Production ready** - PostgreSQL and SQLite support
|
|
362
69
|
|
|
363
|
-
##
|
|
70
|
+
## Documentation
|
|
364
71
|
|
|
365
|
-
-
|
|
366
|
-
|
|
367
|
-
-
|
|
368
|
-
-
|
|
369
|
-
|
|
72
|
+
- [Documentation](https://openworkflow.dev/docs)
|
|
73
|
+
- [Quick Start Guide](https://openworkflow.dev/docs/quickstart)
|
|
74
|
+
- [Core Concepts](https://openworkflow.dev/docs/core-concepts)
|
|
75
|
+
- [Advanced Patterns](https://openworkflow.dev/docs/advanced-patterns)
|
|
76
|
+
- [Production Checklist](https://openworkflow.dev/docs/production)
|
|
370
77
|
|
|
371
|
-
##
|
|
78
|
+
## Architecture
|
|
372
79
|
|
|
373
|
-
|
|
80
|
+
Read
|
|
81
|
+
[ARCHITECTURE.md](https://github.com/openworkflowdev/openworkflow/blob/main/ARCHITECTURE.md)
|
|
82
|
+
for a deep dive into how OpenWorkflow works under the hood.
|
|
374
83
|
|
|
375
|
-
|
|
376
|
-
- ✅ CLI (`npx @openworkflow/cli`)
|
|
377
|
-
- ✅ Worker with concurrency control
|
|
378
|
-
- ✅ Step memoization & retries
|
|
379
|
-
- ✅ Graceful shutdown
|
|
380
|
-
- ✅ Parallel step execution
|
|
381
|
-
- ✅ Sleeping (pausing) workflows
|
|
382
|
-
- ✅ Workflow versioning
|
|
383
|
-
- ✅ Workflow cancelation
|
|
84
|
+
## Examples
|
|
384
85
|
|
|
385
|
-
|
|
86
|
+
Check out
|
|
87
|
+
[examples/](https://github.com/openworkflowdev/openworkflow/tree/main/examples)
|
|
88
|
+
for working examples.
|
|
386
89
|
|
|
387
|
-
|
|
388
|
-
> workflow and step state directly in PostgreSQL or SQLite (workflow_runs and
|
|
389
|
-
> step_attempts tables). A dashboard is planned for an upcoming release to make
|
|
390
|
-
> debugging and monitoring much easier.
|
|
90
|
+
## Contributing
|
|
391
91
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
- Configurable retry policies
|
|
396
|
-
- Signals for external events
|
|
397
|
-
- Native OpenTelemetry integration
|
|
398
|
-
- Additional backends (Redis)
|
|
399
|
-
- Additional languages (Go, Python)
|
|
92
|
+
We welcome contributions! Please read
|
|
93
|
+
[CONTRIBUTING.md](https://github.com/openworkflowdev/openworkflow/blob/main/CONTRIBUTING.md)
|
|
94
|
+
before submitting a pull request.
|
|
400
95
|
|
|
401
|
-
##
|
|
96
|
+
## Community
|
|
402
97
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
https://
|
|
98
|
+
- [GitHub Issues](https://github.com/openworkflowdev/openworkflow/issues) -
|
|
99
|
+
Report bugs and request features
|
|
100
|
+
- [Roadmap](https://openworkflow.dev/docs/roadmap) - See what's coming next
|
package/dist/backend.js
CHANGED
package/dist/bin/openworkflow.js
CHANGED
package/dist/client.js
CHANGED
package/dist/core/duration.js
CHANGED
package/dist/core/error.js
CHANGED
package/dist/core/json.js
CHANGED
package/dist/core/result.js
CHANGED
package/dist/core/retry.js
CHANGED
package/dist/core/schema.js
CHANGED
package/dist/core/step.js
CHANGED
package/dist/core/workflow.js
CHANGED
package/dist/execution.js
CHANGED
package/dist/index.js
CHANGED
package/dist/internal.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export type { Workflow } from "./workflow.js";
|
|
2
2
|
export { isWorkflow } from "./workflow.js";
|
|
3
|
-
export
|
|
4
|
-
export type {
|
|
5
|
-
export type {
|
|
6
|
-
export type { StepAttempt } from "./core/step.js";
|
|
7
|
-
export { DEFAULT_RETRY_POLICY } from "./core/retry.js";
|
|
3
|
+
export type { Backend, PaginationOptions, PaginatedResponse, } from "./backend.js";
|
|
4
|
+
export type { WorkflowRun, WorkflowRunStatus } from "./core/workflow.js";
|
|
5
|
+
export type { StepAttempt, StepAttemptStatus, StepKind } from "./core/step.js";
|
|
8
6
|
//# sourceMappingURL=internal.d.ts.map
|
package/dist/internal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../internal.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../internal.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,YAAY,EACV,OAAO,EACP,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAGtB,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACzE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/internal.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { Backend, CancelWorkflowRunParams, ClaimWorkflowRunParams, CreateStepAttemptParams, CreateWorkflowRunParams, GetStepAttemptParams, GetWorkflowRunParams, ExtendWorkflowRunLeaseParams, ListStepAttemptsParams, ListWorkflowRunsParams, PaginatedResponse, FailStepAttemptParams, CompleteStepAttemptParams, FailWorkflowRunParams, CompleteWorkflowRunParams, SleepWorkflowRunParams
|
|
1
|
+
import { Backend, CancelWorkflowRunParams, ClaimWorkflowRunParams, CreateStepAttemptParams, CreateWorkflowRunParams, GetStepAttemptParams, GetWorkflowRunParams, ExtendWorkflowRunLeaseParams, ListStepAttemptsParams, ListWorkflowRunsParams, PaginatedResponse, FailStepAttemptParams, CompleteStepAttemptParams, FailWorkflowRunParams, CompleteWorkflowRunParams, SleepWorkflowRunParams } from "../backend.js";
|
|
2
|
+
import { StepAttempt } from "../core/step.js";
|
|
3
|
+
import { WorkflowRun } from "../core/workflow.js";
|
|
2
4
|
interface BackendPostgresOptions {
|
|
3
5
|
namespaceId?: string;
|
|
4
6
|
runMigrations?: boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../postgres/backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,OAAO,EACP,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,4BAA4B,EAC5B,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAWlD,UAAU,sBAAsB;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,eAAgB,YAAW,OAAO;IAC7C,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO;IAKP;;;;;;;OAOG;WACU,OAAO,CAClB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,eAAe,CAAC;IAiBrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IA0CjB,cAAc,CAClB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAYxB,gBAAgB,CACpB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IA2B1C,OAAO,CAAC,0BAA0B;IA0B5B,gBAAgB,CACpB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAmDxB,sBAAsB,CAC1B,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,WAAW,CAAC;IAkBjB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IAwBtE,mBAAmB,CACvB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,WAAW,CAAC;IAuBjB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;IAgEpE,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IA2CjB,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAoCjB,cAAc,CAClB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAWxB,gBAAgB,CACpB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IA2B1C,OAAO,CAAC,0BAA0B;IA6BlC,OAAO,CAAC,wBAAwB;IAyC1B,mBAAmB,CACvB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,WAAW,CAAC;IA0BjB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;CAyB3E"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { DEFAULT_NAMESPACE_ID, } from "../backend.js";
|
|
2
|
+
import { DEFAULT_RETRY_POLICY } from "../core/retry.js";
|
|
1
3
|
import { newPostgres, newPostgresMaxOne, migrate, DEFAULT_SCHEMA, } from "./postgres.js";
|
|
2
|
-
import { DEFAULT_NAMESPACE_ID, DEFAULT_RETRY_POLICY, } from "openworkflow/internal";
|
|
3
4
|
const DEFAULT_PAGINATION_PAGE_SIZE = 100;
|
|
4
5
|
/**
|
|
5
6
|
* Manages a connection to a Postgres database for workflow operations.
|
|
@@ -98,8 +99,8 @@ export class BackendPostgres {
|
|
|
98
99
|
}
|
|
99
100
|
const whereClause = this.buildListWorkflowRunsWhere(params, cursor);
|
|
100
101
|
const order = before
|
|
101
|
-
? this.pg `ORDER BY "created_at"
|
|
102
|
-
: this.pg `ORDER BY "created_at"
|
|
102
|
+
? this.pg `ORDER BY "created_at" ASC, "id" ASC`
|
|
103
|
+
: this.pg `ORDER BY "created_at" DESC, "id" DESC`;
|
|
103
104
|
const rows = await this.pg `
|
|
104
105
|
SELECT *
|
|
105
106
|
FROM "openworkflow"."workflow_runs"
|
|
@@ -113,7 +114,7 @@ export class BackendPostgres {
|
|
|
113
114
|
const { after } = params;
|
|
114
115
|
const conditions = [this.pg `"namespace_id" = ${this.namespaceId}`];
|
|
115
116
|
if (cursor) {
|
|
116
|
-
const op = after ? this.pg
|
|
117
|
+
const op = after ? this.pg `<` : this.pg `>`;
|
|
117
118
|
conditions.push(this.pg `("created_at", "id") ${op} (${cursor.createdAt}, ${cursor.id})`);
|
|
118
119
|
}
|
|
119
120
|
let whereClause = conditions[0];
|
|
@@ -531,4 +532,3 @@ function decodeCursor(cursor) {
|
|
|
531
532
|
id: parsed.id,
|
|
532
533
|
};
|
|
533
534
|
}
|
|
534
|
-
//# sourceMappingURL=backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../postgres/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,eAAO,MAAM,oBAAoB,2DACyB,CAAC;AAO3D,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AACnD,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7D;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,oBAEjE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,oBAEvE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CA+JnD;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAQzD;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAE5D"}
|
|
@@ -231,4 +231,3 @@ async function getCurrentMigrationVersion(pg, schema) {
|
|
|
231
231
|
const currentVersionRes = await pg.unsafe(`SELECT MAX("version") AS "version" FROM "${schema}"."openworkflow_migrations";`);
|
|
232
232
|
return currentVersionRes[0]?.version ?? -1;
|
|
233
233
|
}
|
|
234
|
-
//# sourceMappingURL=postgres.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-migrate.d.ts","sourceRoot":"","sources":["../../../postgres/scripts/db-migrate.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-reset.d.ts","sourceRoot":"","sources":["../../../postgres/scripts/db-reset.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"squawk.d.ts","sourceRoot":"","sources":["../../../
|
|
1
|
+
{"version":3,"file":"squawk.d.ts","sourceRoot":"","sources":["../../../postgres/scripts/squawk.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/postgres.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BackendPostgres } from "./postgres/backend.js";
|
package/dist/registry.js
CHANGED
package/dist/sqlite/backend.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { Backend, CancelWorkflowRunParams, ClaimWorkflowRunParams, CreateStepAttemptParams, CreateWorkflowRunParams, GetStepAttemptParams, GetWorkflowRunParams, ExtendWorkflowRunLeaseParams, ListStepAttemptsParams, ListWorkflowRunsParams, PaginatedResponse, FailStepAttemptParams, CompleteStepAttemptParams, FailWorkflowRunParams, CompleteWorkflowRunParams, SleepWorkflowRunParams
|
|
1
|
+
import { Backend, CancelWorkflowRunParams, ClaimWorkflowRunParams, CreateStepAttemptParams, CreateWorkflowRunParams, GetStepAttemptParams, GetWorkflowRunParams, ExtendWorkflowRunLeaseParams, ListStepAttemptsParams, ListWorkflowRunsParams, PaginatedResponse, FailStepAttemptParams, CompleteStepAttemptParams, FailWorkflowRunParams, CompleteWorkflowRunParams, SleepWorkflowRunParams } from "../backend.js";
|
|
2
|
+
import { StepAttempt } from "../core/step.js";
|
|
3
|
+
import { WorkflowRun } from "../core/workflow.js";
|
|
2
4
|
interface BackendSqliteOptions {
|
|
3
5
|
namespaceId?: string;
|
|
4
6
|
runMigrations?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../sqlite/backend.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../sqlite/backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,OAAO,EACP,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,4BAA4B,EAC5B,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAgBlD,UAAU,oBAAoB;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,aAAc,YAAW,OAAO;IAC3C,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO;IAKP;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa;IAiBrE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAgDvB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAenE,gBAAgB,CACpB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA0FxB,sBAAsB,CAC1B,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,WAAW,CAAC;IAmCjB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IAoCtE,mBAAmB,CACvB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,WAAW,CAAC;IAyCjB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;IA+DpE,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAuDvB,gBAAgB,CACd,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAgE1C,gBAAgB,CACd,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAmE1C,OAAO,CAAC,wBAAwB;IAyC1B,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAwCvB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAenE,mBAAmB,CACvB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,WAAW,CAAC;IA0DjB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;CAyD3E"}
|