@dudousxd/nestjs-durable 0.47.1 → 0.48.0
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/dist/index.cjs +519 -283
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -5
- package/dist/index.d.ts +75 -5
- package/dist/index.js +432 -200
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/skills/durable-workflows/SKILL.md +37 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dudousxd/nestjs-durable",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.0",
|
|
4
4
|
"description": "Durable workflows for NestJS — module, decorators, discovery and boot recovery",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Davide Carvalho",
|
|
@@ -67,9 +67,10 @@
|
|
|
67
67
|
"tsup": "8.3.5",
|
|
68
68
|
"@dudousxd/nestjs-diagnostics": "0.5.0",
|
|
69
69
|
"@tanstack/intent": "0.4.0",
|
|
70
|
-
"@dudousxd/durable-worker": "0.
|
|
71
|
-
"@dudousxd/nestjs-durable-core": "^0.
|
|
72
|
-
"@dudousxd/nestjs-durable-dashboard": "0.
|
|
70
|
+
"@dudousxd/durable-worker": "0.11.0",
|
|
71
|
+
"@dudousxd/nestjs-durable-core": "^0.79.0",
|
|
72
|
+
"@dudousxd/nestjs-durable-dashboard": "0.51.0",
|
|
73
|
+
"@dudousxd/nestjs-durable-testing": "^0.18.0",
|
|
73
74
|
"@dudousxd/nestjs-durable-transport-bullmq": "0.22.1",
|
|
74
75
|
"@dudousxd/nestjs-durable-transport-event-emitter": "^0.5.1"
|
|
75
76
|
},
|
|
@@ -146,6 +146,17 @@ outputs in input order (a `GatherError` carries the failed indexes, as for a chi
|
|
|
146
146
|
const results = await ctx.all(this.lines.processLine, lines, { concurrency: 500 });
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
+
When a failed item is an expected outcome rather than a reason to fail the run, use
|
|
150
|
+
`ctx.allSettled` instead: the same fan, resolving with `{ status: 'fulfilled', value }` or
|
|
151
|
+
`{ status: 'rejected', id, error, code?, details? }` per input, in input order, and never throwing for an item. The rejected `code`/`details` are the `FatalError`'s (absent for a plain `Error`). Throw
|
|
152
|
+
`FatalError` in the step for a failure a retry can't fix (a schema mismatch); it settles as rejected
|
|
153
|
+
without spending the retries:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
const results = await ctx.allSettled(this.lines.validateLine, lines, { concurrency: 500 });
|
|
157
|
+
const rejected = results.filter((r) => r.status === 'rejected');
|
|
158
|
+
```
|
|
159
|
+
|
|
149
160
|
Prefer it to `Promise.all` past a handful of steps: every result of a `Promise.all` replays the
|
|
150
161
|
workflow, which makes a fan of N steps cost O(N²) checkpoint reads. Prefer it to a child-workflow
|
|
151
162
|
`ctx.all` when each item is just a step: a child costs a whole run (row, turn, lease, signal).
|
|
@@ -213,7 +224,7 @@ const rows = await ctx.child<{ rows: number }>('processing', { baseId });
|
|
|
213
224
|
`ctx.child` starts the child once (checkpointed) and suspends — zero compute — until it reaches a
|
|
214
225
|
terminal state, then resumes with its output (or throws if the child failed). Use `ctx.all(Class,
|
|
215
226
|
inputs)` / `ctx.all(name, inputs)` to fan out N children of the same workflow and wait for all of
|
|
216
|
-
them.
|
|
227
|
+
them, or `ctx.allSettled(...)` to get every outcome back instead of a `GatherError`.
|
|
217
228
|
|
|
218
229
|
## Common mistakes
|
|
219
230
|
|
|
@@ -276,4 +287,29 @@ async charge(order: Order) {
|
|
|
276
287
|
```
|
|
277
288
|
|
|
278
289
|
Any thrown error is retried to the step's limit; only `FatalError` short-circuits retries.
|
|
290
|
+
|
|
291
|
+
When a failure is an expected outcome rather than a reason to fail the run (a line that fails
|
|
292
|
+
validation), route its code to an `@OnError` handler. The engine starts the handler workflow
|
|
293
|
+
(`<workflow>.onError.<method>`) as run `<runId>.onError.<attempt>` with `{ runId, workflow, input, error }`
|
|
294
|
+
when the run fails with that code, and the run settles with the handler's outcome (its output, or
|
|
295
|
+
its error when the handler fails); the body never runs again, so a `ctx.all` over the workflow
|
|
296
|
+
keeps going. It works for remote (Python) bodies too:
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
class InvalidLine extends FatalError {
|
|
300
|
+
static readonly code = 'invalid_line';
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@OnError(InvalidLine) // or @OnError('invalid_line'); @OnError() catches anything else
|
|
304
|
+
async invalid(ctx: WorkflowCtx, failure: OnErrorInput<Line>): Promise<LineResult> {
|
|
305
|
+
await ctx.step(this.steps.recordDeadLetter, { line: failure.input, error: failure.error.message });
|
|
306
|
+
return { ok: 0, failed: 1 };
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
`error.details` is the third argument of `FatalError(message, code, details)` (e.g. validation
|
|
311
|
+
issues). Retrying the run runs its body again; a new failure goes to a new handler run.
|
|
312
|
+
It matches on `code`, never `instanceof`, must return `run`'s output type, and never sees
|
|
313
|
+
cancellation (a `cancelled` run never routes), `nested_workflow_call` ctx misuse, or `non_determinism`
|
|
314
|
+
(`NonDeterminismError` carries `code: 'non_determinism'`). `@Workflow({ onError: [{ code, workflow }] })` routes to another workflow.
|
|
279
315
|
Source: packages/core/src/workflow-ctx.ts (`step` retry loop), packages/core/src/errors.ts.
|