From 836170b4f661a13d9cdc018c979f6ed1fbb090e2 Mon Sep 17 00:00:00 2001 From: coji Date: Thu, 5 Mar 2026 09:26:30 +0900 Subject: [PATCH 1/5] feat: distinguish cancelled steps from failed steps with step:cancel event (#39) When a run is cancelled while a step is executing, the step is now recorded as 'cancelled' instead of 'failed' and emits a 'step:cancel' event instead of 'step:fail'. Detection uses controller.signal.aborted so user-initiated AbortErrors (e.g. fetch timeouts) are unaffected. Co-Authored-By: Claude Opus 4.6 --- packages/durably-react/src/client/use-runs.ts | 13 ++- packages/durably-react/src/hooks/use-runs.ts | 1 + packages/durably-react/src/types.ts | 7 ++ packages/durably/docs/llms.md | 1 + packages/durably/src/context.ts | 36 +++++--- packages/durably/src/events.ts | 11 +++ packages/durably/src/index.ts | 1 + packages/durably/src/schema.ts | 2 +- packages/durably/src/server.ts | 13 +++ packages/durably/src/storage.ts | 4 +- packages/durably/tests/shared/step.shared.ts | 82 +++++++++++++++++++ website/api/events.md | 19 +++++ website/public/llms.txt | 1 + 13 files changed, 175 insertions(+), 16 deletions(-) diff --git a/packages/durably-react/src/client/use-runs.ts b/packages/durably-react/src/client/use-runs.ts index 531beda6..b8b890c9 100644 --- a/packages/durably-react/src/client/use-runs.ts +++ b/packages/durably-react/src/client/use-runs.ts @@ -42,6 +42,13 @@ type RunUpdateEvent = stepIndex: number error: string } + | { + type: 'step:cancel' + runId: string + jobName: string + stepName: string + stepIndex: number + } | { type: 'log:write' runId: string @@ -321,7 +328,11 @@ export function useRuns< ) } // On step start or fail, refresh to get latest state - if (data.type === 'step:start' || data.type === 'step:fail') { + if ( + data.type === 'step:start' || + data.type === 'step:fail' || + data.type === 'step:cancel' + ) { refresh() } // log:write is handled by useJobLogs, not useRuns diff --git a/packages/durably-react/src/hooks/use-runs.ts b/packages/durably-react/src/hooks/use-runs.ts index 7f610956..9d266ee3 100644 --- a/packages/durably-react/src/hooks/use-runs.ts +++ b/packages/durably-react/src/hooks/use-runs.ts @@ -208,6 +208,7 @@ export function useRuns< durably.on('run:progress', refresh), durably.on('step:start', refresh), durably.on('step:complete', refresh), + durably.on('step:cancel', refresh), ] return () => { diff --git a/packages/durably-react/src/types.ts b/packages/durably-react/src/types.ts index 69a17062..b0720afd 100644 --- a/packages/durably-react/src/types.ts +++ b/packages/durably-react/src/types.ts @@ -93,6 +93,13 @@ export type DurablyEvent = stepIndex: number output: unknown } + | { + type: 'step:cancel' + runId: string + jobName: string + stepName: string + stepIndex: number + } | { type: 'log:write' runId: string diff --git a/packages/durably/docs/llms.md b/packages/durably/docs/llms.md index cb4f9169..4df683a3 100644 --- a/packages/durably/docs/llms.md +++ b/packages/durably/docs/llms.md @@ -236,6 +236,7 @@ durably.on('run:progress', (e) => durably.on('step:start', (e) => console.log('Step:', e.stepName)) durably.on('step:complete', (e) => console.log('Step done:', e.stepName)) durably.on('step:fail', (e) => console.error('Step failed:', e.stepName)) +durably.on('step:cancel', (e) => console.log('Step cancelled:', e.stepName)) // Log events durably.on('log:write', (e) => console.log(`[${e.level}]`, e.message)) diff --git a/packages/durably/src/context.ts b/packages/durably/src/context.ts index 3cb370ac..deaebee8 100644 --- a/packages/durably/src/context.ts +++ b/packages/durably/src/context.ts @@ -106,7 +106,7 @@ export function createStepContext( return result } catch (error) { - // Save failed step + const isCancelled = controller.signal.aborted const errorMessage = error instanceof Error ? error.message : String(error) @@ -114,21 +114,33 @@ export function createStepContext( runId: run.id, name, index: stepIndex, - status: 'failed', + status: isCancelled ? 'cancelled' : 'failed', error: errorMessage, startedAt, }) - // Emit step:fail event - eventEmitter.emit({ - type: 'step:fail', - runId: run.id, - jobName, - stepName: name, - stepIndex, - error: errorMessage, - labels: run.labels, - }) + if (isCancelled) { + // Emit step:cancel event + eventEmitter.emit({ + type: 'step:cancel', + runId: run.id, + jobName, + stepName: name, + stepIndex, + labels: run.labels, + }) + } else { + // Emit step:fail event + eventEmitter.emit({ + type: 'step:fail', + runId: run.id, + jobName, + stepName: name, + stepIndex, + error: errorMessage, + labels: run.labels, + }) + } throw error } finally { diff --git a/packages/durably/src/events.ts b/packages/durably/src/events.ts index fa933014..71cc035f 100644 --- a/packages/durably/src/events.ts +++ b/packages/durably/src/events.ts @@ -133,6 +133,15 @@ export interface StepFailEvent extends BaseEvent { labels: Record } +export interface StepCancelEvent extends BaseEvent { + type: 'step:cancel' + runId: string + jobName: string + stepName: string + stepIndex: number + labels: Record +} + /** * Log write event */ @@ -172,6 +181,7 @@ export type DurablyEvent = | StepStartEvent | StepCompleteEvent | StepFailEvent + | StepCancelEvent | LogWriteEvent | WorkerErrorEvent @@ -211,6 +221,7 @@ export type AnyEventInput = | EventInput<'step:start'> | EventInput<'step:complete'> | EventInput<'step:fail'> + | EventInput<'step:cancel'> | EventInput<'log:write'> | EventInput<'worker:error'> diff --git a/packages/durably/src/index.ts b/packages/durably/src/index.ts index 1c0b81f3..0a1f4561 100644 --- a/packages/durably/src/index.ts +++ b/packages/durably/src/index.ts @@ -25,6 +25,7 @@ export type { RunFailEvent, RunProgressEvent, RunStartEvent, + StepCancelEvent, StepCompleteEvent, StepFailEvent, StepStartEvent, diff --git a/packages/durably/src/schema.ts b/packages/durably/src/schema.ts index b53e450c..e77d9e06 100644 --- a/packages/durably/src/schema.ts +++ b/packages/durably/src/schema.ts @@ -26,7 +26,7 @@ export interface StepsTable { run_id: string name: string index: number - status: 'completed' | 'failed' + status: 'completed' | 'failed' | 'cancelled' output: string | null // JSON error: string | null started_at: string // ISO8601 diff --git a/packages/durably/src/server.ts b/packages/durably/src/server.ts index 618b95dc..d73bc434 100644 --- a/packages/durably/src/server.ts +++ b/packages/durably/src/server.ts @@ -515,6 +515,19 @@ export function createDurablyHandler( } }), + durably.on('step:cancel', (event) => { + if (matchesFilter(event.jobName, event.labels)) { + ctrl.enqueue({ + type: 'step:cancel', + runId: event.runId, + jobName: event.jobName, + stepName: event.stepName, + stepIndex: event.stepIndex, + labels: event.labels, + }) + } + }), + durably.on('log:write', (event) => { if (matchesFilter(event.jobName, event.labels)) { ctrl.enqueue({ diff --git a/packages/durably/src/storage.ts b/packages/durably/src/storage.ts index 062091ef..7530f177 100644 --- a/packages/durably/src/storage.ts +++ b/packages/durably/src/storage.ts @@ -72,7 +72,7 @@ export interface CreateStepInput { runId: string name: string index: number - status: 'completed' | 'failed' + status: 'completed' | 'failed' | 'cancelled' output?: unknown error?: string startedAt: string // ISO8601 timestamp when step execution started @@ -86,7 +86,7 @@ export interface Step { runId: string name: string index: number - status: 'completed' | 'failed' + status: 'completed' | 'failed' | 'cancelled' output: unknown | null error: string | null startedAt: string diff --git a/packages/durably/tests/shared/step.shared.ts b/packages/durably/tests/shared/step.shared.ts index f6468fa3..faa173df 100644 --- a/packages/durably/tests/shared/step.shared.ts +++ b/packages/durably/tests/shared/step.shared.ts @@ -6,7 +6,9 @@ import { defineJob, type Durably, type RunProgressEvent, + type StepCancelEvent, type StepCompleteEvent, + type StepFailEvent, } from '../../src' export function createStepTests(createDialect: () => Dialect) { @@ -456,6 +458,86 @@ export function createStepTests(createDialect: () => Dialect) { ) }) + it('emits step:cancel event when step is cancelled', async () => { + const cancelEvents: StepCancelEvent[] = [] + const failEvents: StepFailEvent[] = [] + let stepStartedResolve!: () => void + const stepStartedPromise = new Promise((resolve) => { + stepStartedResolve = resolve + }) + + const stepCancelEventDef = defineJob({ + name: 'step-cancel-event-test', + input: z.object({}), + run: async (step) => { + await step.run('cancellable-step', async (signal) => { + stepStartedResolve() + await new Promise((_resolve, reject) => { + signal.addEventListener('abort', () => { + reject( + new DOMException('The operation was aborted.', 'AbortError'), + ) + }) + }) + }) + }, + }) + const d = durably.register({ job: stepCancelEventDef }) + + d.on('step:cancel', (event) => cancelEvents.push(event)) + d.on('step:fail', (event) => failEvents.push(event)) + + const run = await d.jobs.job.trigger({}) + d.start() + + await stepStartedPromise + await d.cancel(run.id) + + await vi.waitFor( + () => { + expect(cancelEvents).toHaveLength(1) + }, + { timeout: 2000 }, + ) + + expect(cancelEvents[0].stepName).toBe('cancellable-step') + expect(cancelEvents[0].runId).toBe(run.id) + expect(failEvents).toHaveLength(0) + }) + + it('emits step:fail event for non-cancellation errors', async () => { + const cancelEvents: StepCancelEvent[] = [] + const failEvents: StepFailEvent[] = [] + + const stepFailEventDef = defineJob({ + name: 'step-fail-event-test', + input: z.object({}), + run: async (step) => { + await step.run('failing-step', async () => { + throw new Error('intentional error') + }) + }, + }) + const d = durably.register({ job: stepFailEventDef }) + + d.on('step:cancel', (event) => cancelEvents.push(event)) + d.on('step:fail', (event) => failEvents.push(event)) + + await d.jobs.job.trigger({}) + d.start() + + await vi.waitFor( + () => { + expect(failEvents).toHaveLength(1) + }, + { timeout: 2000 }, + ) + + expect(failEvents[0].stepName).toBe('failing-step') + expect(failEvents[0].error).toBe('intentional error') + expect(cancelEvents).toHaveLength(0) + }) + it('signal is aborted when cancellation is detected at step boundary', async () => { let step2Called = false let step1StartedResolve!: () => void diff --git a/website/api/events.md b/website/api/events.md index 33203562..979c4cbb 100644 --- a/website/api/events.md +++ b/website/api/events.md @@ -217,6 +217,25 @@ durably.on('step:fail', (event) => { }) ``` +#### `step:cancel` + +Fired when a step is cancelled (run was cancelled while step was executing). + +```ts +durably.on('step:cancel', (event) => { + // event: { + // type: 'step:cancel', + // runId: string, + // jobName: string, + // stepName: string, + // stepIndex: number, + // labels: Record, + // timestamp: string, + // sequence: number + // } +}) +``` + ### Log Events #### `log:write` diff --git a/website/public/llms.txt b/website/public/llms.txt index 78d21308..45415140 100644 --- a/website/public/llms.txt +++ b/website/public/llms.txt @@ -236,6 +236,7 @@ durably.on('run:progress', (e) => durably.on('step:start', (e) => console.log('Step:', e.stepName)) durably.on('step:complete', (e) => console.log('Step done:', e.stepName)) durably.on('step:fail', (e) => console.error('Step failed:', e.stepName)) +durably.on('step:cancel', (e) => console.log('Step cancelled:', e.stepName)) // Log events durably.on('log:write', (e) => console.log(`[${e.level}]`, e.message)) From 8bed946b2c0801b72ea48be2e05c57fd6ba8dedc Mon Sep 17 00:00:00 2001 From: coji Date: Thu, 5 Mar 2026 10:16:28 +0900 Subject: [PATCH 2/5] docs: add cancelled to StepRecord status in react types docs Co-Authored-By: Claude Opus 4.6 --- website/api/durably-react/types.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/website/api/durably-react/types.md b/website/api/durably-react/types.md index 35222a48..7fbe9bbf 100644 --- a/website/api/durably-react/types.md +++ b/website/api/durably-react/types.md @@ -99,7 +99,7 @@ interface ClientRun { ```ts interface StepRecord { name: string - status: 'completed' | 'failed' + status: 'completed' | 'failed' | 'cancelled' output: unknown error: string | null startedAt: string @@ -107,11 +107,11 @@ interface StepRecord { } ``` -| Property | Type | Description | -| ------------- | ------------------------- | --------------------------- | -| `name` | `string` | Step name | -| `status` | `'completed' \| 'failed'` | Step result | -| `output` | `unknown` | Step return value | -| `error` | `string \| null` | Error message (when failed) | -| `startedAt` | `string` | ISO timestamp of start | -| `completedAt` | `string \| null` | ISO timestamp of completion | +| Property | Type | Description | +| ------------- | ---------------------------------------- | --------------------------- | +| `name` | `string` | Step name | +| `status` | `'completed' \| 'failed' \| 'cancelled'` | Step result | +| `output` | `unknown` | Step return value | +| `error` | `string \| null` | Error message (when failed) | +| `startedAt` | `string` | ISO timestamp of start | +| `completedAt` | `string \| null` | ISO timestamp of completion | From 4c4c5fa683462fd934f2f68ba2972e8d4a6b575e Mon Sep 17 00:00:00 2001 From: coji Date: Thu, 5 Mar 2026 10:21:03 +0900 Subject: [PATCH 3/5] refactor: unify step cancel/fail event emission in catch block Co-Authored-By: Claude Opus 4.6 --- packages/durably/src/context.ts | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/packages/durably/src/context.ts b/packages/durably/src/context.ts index deaebee8..96f73aaa 100644 --- a/packages/durably/src/context.ts +++ b/packages/durably/src/context.ts @@ -119,28 +119,16 @@ export function createStepContext( startedAt, }) - if (isCancelled) { - // Emit step:cancel event - eventEmitter.emit({ - type: 'step:cancel', - runId: run.id, - jobName, - stepName: name, - stepIndex, - labels: run.labels, - }) - } else { - // Emit step:fail event - eventEmitter.emit({ - type: 'step:fail', - runId: run.id, - jobName, - stepName: name, - stepIndex, - error: errorMessage, - labels: run.labels, - }) - } + eventEmitter.emit({ + ...(isCancelled + ? { type: 'step:cancel' as const } + : { type: 'step:fail' as const, error: errorMessage }), + runId: run.id, + jobName, + stepName: name, + stepIndex, + labels: run.labels, + }) throw error } finally { From ceb182c199f63a3f414391009d15fef200b6a4b9 Mon Sep 17 00:00:00 2001 From: coji Date: Thu, 5 Mar 2026 12:02:57 +0900 Subject: [PATCH 4/5] fix: address CodeRabbit review comments - Add labels to step:cancel in DurablyEvent type (types.ts) - Add cancelled to StepRecord.status (use-run-actions.ts) - Rethrow CancelledError instead of original error on cancellation (context.ts) - Add StepCancelEvent to DurablyEvent union in docs (events.md) Co-Authored-By: Claude Opus 4.6 --- packages/durably-react/src/client/use-run-actions.ts | 2 +- packages/durably-react/src/types.ts | 1 + packages/durably/src/context.ts | 3 +++ website/api/events.md | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/durably-react/src/client/use-run-actions.ts b/packages/durably-react/src/client/use-run-actions.ts index 26f80f30..03f06ef4 100644 --- a/packages/durably-react/src/client/use-run-actions.ts +++ b/packages/durably-react/src/client/use-run-actions.ts @@ -6,7 +6,7 @@ import type { ClientRun } from '../types' */ export interface StepRecord { name: string - status: 'completed' | 'failed' + status: 'completed' | 'failed' | 'cancelled' output: unknown } diff --git a/packages/durably-react/src/types.ts b/packages/durably-react/src/types.ts index b0720afd..f31c6ef5 100644 --- a/packages/durably-react/src/types.ts +++ b/packages/durably-react/src/types.ts @@ -99,6 +99,7 @@ export type DurablyEvent = jobName: string stepName: string stepIndex: number + labels: Record } | { type: 'log:write' diff --git a/packages/durably/src/context.ts b/packages/durably/src/context.ts index 96f73aaa..5e56fcd8 100644 --- a/packages/durably/src/context.ts +++ b/packages/durably/src/context.ts @@ -130,6 +130,9 @@ export function createStepContext( labels: run.labels, }) + if (isCancelled) { + throw new CancelledError(run.id) + } throw error } finally { // Clear current step after execution diff --git a/website/api/events.md b/website/api/events.md index 979c4cbb..9bc88d0a 100644 --- a/website/api/events.md +++ b/website/api/events.md @@ -310,6 +310,7 @@ type DurablyEvent = | StepStartEvent | StepCompleteEvent | StepFailEvent + | StepCancelEvent | LogWriteEvent | WorkerErrorEvent ``` From b9050e0860112399d6b7c90a1aa54888e04de687 Mon Sep 17 00:00:00 2001 From: coji Date: Thu, 5 Mar 2026 12:17:46 +0900 Subject: [PATCH 5/5] docs: add step:cancel to examples and guides - Add step:cancel event listener to server-node example and guides - Handle cancelled step status with gray styling in dashboard examples - Add example apps section to doc-check skill Co-Authored-By: Claude Opus 4.6 --- .claude/skills/doc-check/SKILL.md | 33 ++++++++++++++----- .../app/routes/_index/dashboard.tsx | 4 ++- .../src/components/dashboard.tsx | 4 ++- .../app/routes/_index/dashboard.tsx | 4 ++- examples/server-node/basic.ts | 4 +++ website/guide/background-sync.md | 4 +++ website/guide/concepts.md | 2 ++ 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/.claude/skills/doc-check/SKILL.md b/.claude/skills/doc-check/SKILL.md index bc35c5a7..d7618509 100644 --- a/.claude/skills/doc-check/SKILL.md +++ b/.claude/skills/doc-check/SKILL.md @@ -60,6 +60,17 @@ These are the primary references for AI coding agents. | `website/guide/background-sync.md` | Background sync example | | `website/guide/offline-app.md` | Offline app example | +### Example Apps + +Grep for the changed symbol name in `examples/` to find usage. Each example demonstrates a different deployment pattern: + +| Directory | Pattern | Key files | +| ----------------------------------- | ------------------------------ | ------------------------------------------------------------------- | +| `examples/server-node` | Node.js server (core API only) | `jobs/*.ts`, `lib/durably.ts`, `basic.ts` | +| `examples/browser-vite-react` | Browser SPA (Vite + React) | `src/jobs/*.ts`, `src/lib/durably.ts`, `src/components/*.tsx` | +| `examples/browser-react-router-spa` | Browser SPA (React Router) | `app/jobs/*.ts`, `app/lib/durably.ts`, `app/routes/**/*.tsx` | +| `examples/fullstack-react-router` | Fullstack (React Router + SSE) | `app/jobs/*.ts`, `app/lib/durably.server.ts`, `app/routes/**/*.tsx` | + ## 3. Generated Files These are derived from package docs and must be regenerated: @@ -74,15 +85,18 @@ pnpm --filter durably-website generate:llms Use this table to quickly determine which docs to check based on what changed: -| Change Type | Docs to Check | -| -------------------------------- | ------------------------------------------------------------------------------------------ | -| New field on `Run` / `RunFilter` | llms.md (core), create-durably.md, index.md, http-handler.md, react browser.md + client.md | -| New event field | llms.md (core), events.md, index.md | -| New step method | llms.md (core), step.md, index.md | -| New trigger option | llms.md (core), index.md, http-handler.md, create-durably.md | -| React hook change | llms.md (react), browser.md, client.md, index.md (react section) | -| HTTP handler change | llms.md (core), http-handler.md, client.md | -| New config option | llms.md (core), create-durably.md, index.md | +| Change Type | Docs to Check | +| -------------------------------- | ----------------------------------------------------------------------------------------------------- | +| New field on `Run` / `RunFilter` | llms.md (core), create-durably.md, index.md, http-handler.md, react browser.md + client.md | +| New event field | llms.md (core), events.md, index.md | +| New step method | llms.md (core), step.md, index.md | +| New trigger option | llms.md (core), index.md, http-handler.md, create-durably.md | +| React hook change | llms.md (react), browser.md, client.md, index.md (react section) | +| HTTP handler change | llms.md (core), http-handler.md, client.md | +| New config option | llms.md (core), create-durably.md, index.md | +| Job/step API change | All example apps (`examples/`) | +| Event type change | `examples/fullstack-react-router` (SSE), `examples/browser-*` (direct events) | +| React hook change | `examples/browser-vite-react`, `examples/browser-react-router-spa`, `examples/fullstack-react-router` | ## 5. Common Oversights @@ -92,6 +106,7 @@ Use this table to quickly determine which docs to check based on what changed: - **Type definitions** in `website/api/durably-react/types.md` may need new type exports - **`website/public/llms.txt`** is generated — don't edit directly, regenerate instead - **Code examples** in guides may use the changed API — grep for the symbol name in `website/guide/` +- **Example apps** in `examples/` are working apps that use the public API — grep for the changed symbol in all 4 examples ## 6. Verification diff --git a/examples/browser-react-router-spa/app/routes/_index/dashboard.tsx b/examples/browser-react-router-spa/app/routes/_index/dashboard.tsx index 674b6db3..cc86fbb1 100644 --- a/examples/browser-react-router-spa/app/routes/_index/dashboard.tsx +++ b/examples/browser-react-router-spa/app/routes/_index/dashboard.tsx @@ -361,7 +361,9 @@ export function Dashboard() { className={`rounded-full px-2 py-0.5 text-xs font-medium ${ s.status === 'completed' ? 'bg-green-100 text-green-800' - : 'bg-red-100 text-red-800' + : s.status === 'cancelled' + ? 'bg-gray-100 text-gray-800' + : 'bg-red-100 text-red-800' }`} > {s.status} diff --git a/examples/browser-vite-react/src/components/dashboard.tsx b/examples/browser-vite-react/src/components/dashboard.tsx index 1cf3de8e..b78c67bc 100644 --- a/examples/browser-vite-react/src/components/dashboard.tsx +++ b/examples/browser-vite-react/src/components/dashboard.tsx @@ -358,7 +358,9 @@ export function Dashboard() { className={`rounded-full px-2 py-0.5 text-xs font-medium ${ s.status === 'completed' ? 'bg-green-100 text-green-800' - : 'bg-red-100 text-red-800' + : s.status === 'cancelled' + ? 'bg-gray-100 text-gray-800' + : 'bg-red-100 text-red-800' }`} > {s.status} diff --git a/examples/fullstack-react-router/app/routes/_index/dashboard.tsx b/examples/fullstack-react-router/app/routes/_index/dashboard.tsx index 2021f724..1d6d58ec 100644 --- a/examples/fullstack-react-router/app/routes/_index/dashboard.tsx +++ b/examples/fullstack-react-router/app/routes/_index/dashboard.tsx @@ -374,7 +374,9 @@ export function Dashboard() { className={`rounded-full px-2 py-0.5 text-xs font-medium ${ s.status === 'completed' ? 'bg-green-100 text-green-800' - : 'bg-red-100 text-red-800' + : s.status === 'cancelled' + ? 'bg-gray-100 text-gray-800' + : 'bg-red-100 text-red-800' }`} > {s.status} diff --git a/examples/server-node/basic.ts b/examples/server-node/basic.ts index 6f8224ba..bc92a3ee 100644 --- a/examples/server-node/basic.ts +++ b/examples/server-node/basic.ts @@ -16,6 +16,10 @@ durably.on('step:complete', (event) => { console.log(`[step:complete] ${event.stepName}`) }) +durably.on('step:cancel', (event) => { + console.log(`[step:cancel] ${event.stepName}`) +}) + durably.on('run:complete', (event) => { console.log( `[run:complete] output=${JSON.stringify(event.output)} duration=${event.duration}ms`, diff --git a/website/guide/background-sync.md b/website/guide/background-sync.md index 1f3a3890..b96330a9 100644 --- a/website/guide/background-sync.md +++ b/website/guide/background-sync.md @@ -142,6 +142,10 @@ durably.on('step:complete', (event) => { console.log(`[step:complete] ${event.stepName}`) }) +durably.on('step:cancel', (event) => { + console.log(`[step:cancel] ${event.stepName}`) +}) + durably.on('run:complete', (event) => { console.log( `[run:complete] output=${JSON.stringify(event.output)} duration=${event.duration}ms`, diff --git a/website/guide/concepts.md b/website/guide/concepts.md index 843dc142..c61cf64d 100644 --- a/website/guide/concepts.md +++ b/website/guide/concepts.md @@ -198,6 +198,8 @@ durably.on('run:complete', ({ runId, output }) => { ... }) durably.on('run:fail', ({ runId, error }) => { ... }) durably.on('step:start', ({ runId, stepName }) => { ... }) durably.on('step:complete', ({ runId, stepName, output }) => { ... }) +durably.on('step:fail', ({ runId, stepName, error }) => { ... }) +durably.on('step:cancel', ({ runId, stepName }) => { ... }) ``` See [Events API](/api/events) for the full list.