workflow 5.0.0-beta.3 → 5.0.0-beta.30
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/api-workflow.d.ts +1 -1
- package/dist/api-workflow.d.ts.map +1 -1
- package/dist/api-workflow.js +1 -1
- package/dist/api.d.ts +5 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +12 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/internal/builtins.d.ts +17 -0
- package/dist/internal/builtins.d.ts.map +1 -1
- package/dist/internal/builtins.js +65 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +2 -2
- package/dist/runtime.d.ts +2 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +5 -2
- package/docs/ai/chat-session-modeling.mdx +7 -3
- package/docs/ai/defining-tools.mdx +2 -2
- package/docs/ai/index.mdx +28 -23
- package/docs/ai/message-queueing.mdx +10 -10
- package/docs/ai/resumable-streams.mdx +9 -1
- package/docs/api-reference/index.mdx +24 -0
- package/docs/api-reference/meta.json +8 -0
- package/docs/api-reference/vitest/index.mdx +28 -7
- package/docs/api-reference/workflow/create-hook.mdx +38 -0
- package/docs/api-reference/workflow/create-webhook.mdx +1 -0
- package/docs/api-reference/workflow/experimental-set-attributes.mdx +65 -0
- package/docs/api-reference/workflow/fetch.mdx +5 -0
- package/docs/api-reference/workflow/index.mdx +3 -0
- package/docs/api-reference/workflow-ai/durable-agent.mdx +7 -45
- package/docs/api-reference/workflow-ai/index.mdx +2 -2
- package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +44 -1
- package/docs/api-reference/workflow-api/get-hook-by-token.mdx +7 -0
- package/docs/api-reference/workflow-api/get-run.mdx +25 -0
- package/docs/api-reference/workflow-api/index.mdx +6 -8
- package/docs/api-reference/workflow-api/resume-hook.mdx +57 -0
- package/docs/api-reference/workflow-api/start.mdx +13 -5
- package/docs/api-reference/workflow-astro/index.mdx +18 -0
- package/docs/api-reference/workflow-astro/meta.json +4 -0
- package/docs/api-reference/workflow-astro/workflow.mdx +45 -0
- package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
- package/docs/api-reference/workflow-errors/index.mdx +85 -0
- package/docs/api-reference/workflow-errors/meta.json +5 -0
- package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
- package/docs/api-reference/workflow-errors/workflow-error.mdx +52 -0
- package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +16 -6
- package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
- package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
- package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +33 -0
- package/docs/api-reference/workflow-nest/index.mdx +31 -0
- package/docs/api-reference/workflow-nest/meta.json +9 -0
- package/docs/api-reference/workflow-nest/nest-local-builder.mdx +64 -0
- package/docs/api-reference/workflow-nest/workflow-controller.mdx +40 -0
- package/docs/api-reference/workflow-nest/workflow-module.mdx +74 -0
- package/docs/api-reference/workflow-next/with-workflow.mdx +56 -2
- package/docs/api-reference/workflow-nitro/index.mdx +60 -0
- package/docs/api-reference/workflow-nuxt/index.mdx +48 -0
- package/docs/api-reference/workflow-observability/hydrate-data.mdx +35 -0
- package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
- package/docs/api-reference/workflow-observability/index.mdx +64 -0
- package/docs/api-reference/workflow-observability/meta.json +11 -0
- package/docs/api-reference/workflow-observability/observability-revivers.mdx +50 -0
- package/docs/api-reference/workflow-observability/parse-class-name.mdx +41 -0
- package/docs/api-reference/workflow-observability/parse-step-name.mdx +40 -0
- package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
- package/docs/api-reference/workflow-runtime/create-world.mdx +39 -0
- package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/get-world.mdx +7 -10
- package/docs/api-reference/workflow-runtime/health-check.mdx +50 -0
- package/docs/api-reference/workflow-runtime/index.mdx +43 -0
- package/docs/api-reference/workflow-runtime/meta.json +12 -0
- package/docs/api-reference/workflow-runtime/set-world.mdx +49 -0
- package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +42 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/index.mdx +5 -8
- package/docs/api-reference/workflow-runtime/world/meta.json +4 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/queue.mdx +4 -2
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/storage.mdx +11 -4
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/streams.mdx +2 -2
- package/docs/api-reference/workflow-serde/index.mdx +0 -1
- package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +1 -2
- package/docs/api-reference/workflow-serde/workflow-serialize.mdx +1 -2
- package/docs/api-reference/workflow-sveltekit/index.mdx +18 -0
- package/docs/api-reference/workflow-sveltekit/meta.json +4 -0
- package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +42 -0
- package/docs/api-reference/workflow-vite/index.mdx +18 -0
- package/docs/api-reference/workflow-vite/meta.json +4 -0
- package/docs/api-reference/workflow-vite/workflow.mdx +48 -0
- package/docs/changelog/attributes-mvp.mdx +380 -0
- package/docs/changelog/eager-processing.mdx +269 -0
- package/docs/changelog/index.mdx +2 -1
- package/docs/changelog/lazy-event-creation.md +127 -0
- package/docs/changelog/meta.json +8 -1
- package/docs/changelog/resilient-start.mdx +31 -283
- package/docs/changelog/step-message-ownership.mdx +360 -0
- package/docs/changelog/turbo-mode.md +87 -0
- package/docs/configuration/build-and-diagnostics.mdx +51 -0
- package/docs/configuration/cli-and-web-ui.mdx +154 -0
- package/docs/configuration/framework-options.mdx +165 -0
- package/docs/configuration/index.mdx +32 -0
- package/docs/configuration/meta.json +12 -0
- package/docs/configuration/runtime-tuning.mdx +156 -0
- package/docs/configuration/worlds.mdx +228 -0
- package/docs/cookbook/advanced/child-workflows.mdx +199 -256
- package/docs/cookbook/advanced/meta.json +1 -1
- package/docs/cookbook/advanced/publishing-libraries.mdx +13 -12
- package/docs/cookbook/advanced/serializable-steps.mdx +8 -4
- package/docs/cookbook/advanced/upgrading-workflows.mdx +195 -0
- package/docs/cookbook/agent-patterns/agent-cancellation.mdx +31 -76
- package/docs/cookbook/agent-patterns/durable-agent.mdx +11 -143
- package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +7 -3
- package/docs/cookbook/common-patterns/idempotency.mdx +36 -52
- package/docs/cookbook/common-patterns/rate-limiting.mdx +1 -1
- package/docs/cookbook/common-patterns/saga.mdx +2 -2
- package/docs/cookbook/common-patterns/scheduling.mdx +8 -0
- package/docs/cookbook/common-patterns/timeouts.mdx +2 -1
- package/docs/cookbook/common-patterns/workflow-composition.mdx +15 -16
- package/docs/cookbook/index.mdx +3 -3
- package/docs/cookbook/integrations/ai-sdk.mdx +60 -28
- package/docs/cookbook/integrations/chat-sdk.mdx +13 -0
- package/docs/cookbook/integrations/sandbox.mdx +13 -0
- package/docs/deploying/building-a-world.mdx +1 -1
- package/docs/deploying/index.mdx +1 -0
- package/docs/deploying/world/local-world.mdx +23 -6
- package/docs/deploying/world/postgres-world.mdx +79 -13
- package/docs/deploying/world/vercel-world.mdx +47 -12
- package/docs/errors/abort-signal-timeout-in-workflow.mdx +80 -0
- package/docs/errors/corrupted-event-log.mdx +5 -5
- package/docs/errors/hook-conflict.mdx +56 -4
- package/docs/errors/index.mdx +1 -35
- package/docs/errors/replay-divergence.mdx +27 -0
- package/docs/errors/runtime-decryption-failed.mdx +77 -0
- package/docs/errors/step-executed-multiple-times.mdx +23 -0
- package/docs/errors/step-not-registered.mdx +1 -1
- package/docs/foundations/cancellation.mdx +459 -0
- package/docs/foundations/errors-and-retries.mdx +7 -3
- package/docs/foundations/hooks.mdx +29 -0
- package/docs/foundations/idempotency.mdx +236 -11
- package/docs/foundations/index.mdx +1 -23
- package/docs/foundations/meta.json +3 -1
- package/docs/foundations/serialization.mdx +77 -41
- package/docs/foundations/starting-workflows.mdx +5 -1
- package/docs/foundations/streaming.mdx +14 -23
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/getting-started/astro.mdx +6 -0
- package/docs/getting-started/index.mdx +6 -7
- package/docs/getting-started/meta.json +1 -0
- package/docs/getting-started/nestjs.mdx +9 -0
- package/docs/getting-started/next.mdx +5 -3
- package/docs/getting-started/nitro.mdx +22 -0
- package/docs/getting-started/sveltekit.mdx +6 -0
- package/docs/getting-started/tanstack-start.mdx +241 -0
- package/docs/how-it-works/cancellation.mdx +287 -0
- package/docs/how-it-works/code-transform.mdx +2 -2
- package/docs/how-it-works/encryption.mdx +2 -2
- package/docs/how-it-works/event-sourcing.mdx +2 -2
- package/docs/how-it-works/meta.json +2 -1
- package/docs/internal/index.mdx +21 -0
- package/docs/internal/meta.json +10 -0
- package/docs/internal/nitro-native-build.mdx +38 -0
- package/docs/internal/nitro-web-ui.mdx +24 -0
- package/docs/internal/serializable-abort-controller.mdx +148 -0
- package/docs/meta.json +1 -1
- package/docs/migration-guides/migrating-from-aws-step-functions.mdx +7 -12
- package/docs/migration-guides/migrating-from-inngest.mdx +7 -17
- package/docs/migration-guides/migrating-from-temporal.mdx +6 -11
- package/docs/migration-guides/migrating-from-trigger-dev.mdx +8 -17
- package/docs/observability/attributes.mdx +87 -0
- package/docs/observability/index.mdx +18 -1
- package/docs/observability/meta.json +1 -1
- package/docs/observability/tracing.mdx +119 -0
- package/docs/testing/index.mdx +2 -2
- package/package.json +14 -13
- package/docs/api-reference/workflow-api/world/meta.json +0 -4
- package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
- package/docs/cookbook/advanced/distributed-abort-controller.mdx +0 -318
|
@@ -54,11 +54,11 @@ The migration replaces declarative configuration with idiomatic TypeScript and c
|
|
|
54
54
|
| Choice state | `if` / `else` / `switch` | Native TypeScript control flow. |
|
|
55
55
|
| Wait state | `sleep()` | Import `sleep` from `workflow`. |
|
|
56
56
|
| Parallel state | `Promise.all()` | Standard concurrency primitives. |
|
|
57
|
-
| Map state | Inline sequential → `for` loop; bounded parallel (`MaxConcurrency: N`) → batched `Promise.all` or a concurrency limiter like `p-limit`; Distributed Map / large fan-out →
|
|
57
|
+
| Map state | Inline sequential → `for` loop; bounded parallel (`MaxConcurrency: N`) → batched `Promise.all` or a concurrency limiter like `p-limit`; Distributed Map / large fan-out → `start()` per item, then step-wrapped `getRun()` to collect. | Match the concurrency mode of the original Map. |
|
|
58
58
|
| Retry / Catch | Step retries, `RetryableError`, `FatalError` | Retry logic moves to step boundaries. |
|
|
59
59
|
| `Catch` to a compensation state | `try`/`catch` in the workflow function, calling compensation steps in reverse order (push/pop a rollback stack) | See [`/docs/foundations/errors-and-retries`](/docs/foundations/errors-and-retries) for the SAGA pattern. |
|
|
60
60
|
| `.waitForTaskToken` | `createHook()` or `createWebhook()` | Hooks for typed signals; webhooks for HTTP. |
|
|
61
|
-
| Child state machine (`StartExecution`) | `"use step"` around `
|
|
61
|
+
| Child state machine (`StartExecution`) | `start()` plus a `"use step"` wrapper around `getRun()` | Return the `Run` object, await its result from another step. |
|
|
62
62
|
| Execution event history | Workflow event log | Same durable replay model. |
|
|
63
63
|
| Progress via DynamoDB / SNS for client polling | `getWritable()` + named streams | Stream durable updates; clients read from the stream. |
|
|
64
64
|
|
|
@@ -213,21 +213,16 @@ return { refundId, status: 'rejected' };
|
|
|
213
213
|
|
|
214
214
|
## Spawn a child workflow
|
|
215
215
|
|
|
216
|
-
In ASL, a parent machine calls `StartExecution` (usually via `.sync` or `.waitForTaskToken`) to launch a child. In
|
|
216
|
+
In ASL, a parent machine calls `StartExecution` (usually via `.sync` or `.waitForTaskToken`) to launch a child. In v5, call `start()` directly from the workflow to launch a child. Wrap `getRun()` and `returnValue` access in a `"use step"` function when you need to await the child result.
|
|
217
217
|
|
|
218
218
|
### Parent starts a child
|
|
219
219
|
|
|
220
220
|
```typescript title="workflow/workflows/parent.ts"
|
|
221
221
|
import { start } from 'workflow/api';
|
|
222
222
|
|
|
223
|
-
async function spawnChild(item: string) {
|
|
224
|
-
'use step'; // [!code highlight]
|
|
225
|
-
return await start(childWorkflow, [item]);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
223
|
export async function parentWorkflow(item: string) {
|
|
229
224
|
'use workflow';
|
|
230
|
-
const run = await
|
|
225
|
+
const run = await start(childWorkflow, [item]); // [!code highlight]
|
|
231
226
|
return { childRunId: run.runId };
|
|
232
227
|
}
|
|
233
228
|
```
|
|
@@ -338,7 +333,7 @@ Delete the ASL JSON, per-task Lambda deployments, IAM roles, and callback queues
|
|
|
338
333
|
## Features without a 1:1 equivalent
|
|
339
334
|
|
|
340
335
|
- **Express workflows.** At-least-once semantics and 5-minute duration make them a poor fit for the SDK's durable replay model. Consider keeping them on Step Functions or migrating to a queue consumer.
|
|
341
|
-
- **Distributed Map state.** Up to 10,000 concurrent child executions with S3 item sources has no 1:1 analog; fan out with
|
|
336
|
+
- **Distributed Map state.** Up to 10,000 concurrent child executions with S3 item sources has no 1:1 analog; fan out with `start()` per item, then `Promise.all` with `p-limit` to bound concurrency.
|
|
342
337
|
- **Optimized AWS service integrations (`arn:aws:states:::dynamodb:*`, `eventbridge:*`, `bedrock:*`, `ecs:runTask.sync`, etc.).** These become regular SDK calls inside `'use step'` functions — credentials, retries, and polling move into the step.
|
|
343
338
|
- **Per-state IAM roles.** ASL lets each state run under its own IAM role. In the SDK, all steps share the deployment's credentials; scope secrets and roles at deployment time.
|
|
344
339
|
- **CloudWatch alarms / X-Ray cross-service traces / CloudWatch Logs retention.** The SDK event log + observability UI replaces orchestrator state transitions, not AWS-wide observability. Keep alarms and traces for other resources.
|
|
@@ -351,8 +346,8 @@ Delete the ASL JSON, per-task Lambda deployments, IAM roles, and callback queues
|
|
|
351
346
|
- Replace Choice states with `if`/`else`/`switch`.
|
|
352
347
|
- Replace Wait states with `sleep()` from `workflow`.
|
|
353
348
|
- Replace Parallel states with `Promise.all()`.
|
|
354
|
-
- Replace Map states based on their concurrency mode: inline sequential → `for` loop; bounded parallel (`MaxConcurrency: N`) → batched `Promise.all` or a concurrency limiter like `p-limit`; Distributed Map / large fan-out →
|
|
355
|
-
- Replace `StartExecution` child machines with `"use step"`
|
|
349
|
+
- Replace Map states based on their concurrency mode: inline sequential → `for` loop; bounded parallel (`MaxConcurrency: N`) → batched `Promise.all` or a concurrency limiter like `p-limit`; Distributed Map / large fan-out → `start()` per item, then step-wrapped `getRun()` to collect.
|
|
350
|
+
- Replace `StartExecution` child machines with direct `start()` calls and a `"use step"` wrapper around `getRun()` when collecting results.
|
|
356
351
|
- Replace `.waitForTaskToken` with `createHook()` (internal callers) or `createWebhook()` (HTTP callers).
|
|
357
352
|
- Move Retry/Catch to step boundaries using `maxRetries`, `RetryableError`, and `FatalError`.
|
|
358
353
|
- Use `getStepMetadata().stepId` as the idempotency key for external side effects.
|
|
@@ -51,10 +51,10 @@ Inngest's event-bus model is loosely coupled — publishers don't know consumers
|
|
|
51
51
|
| `step.run()` | `"use step"` function | Standalone async function with Node.js access. |
|
|
52
52
|
| `step.sleep()` / `step.sleepUntil()` | `sleep()` | `sleep('5m')` for a duration; `sleep(date)` for sleep-until. |
|
|
53
53
|
| `step.waitForEvent()` | `createHook()` or `createWebhook()` | Hooks for typed signals, webhooks for HTTP. |
|
|
54
|
-
| `step.invoke()` | `"use step"`
|
|
54
|
+
| `step.invoke()` | `start()` plus a `"use step"` wrapper around `getRun()` | Spawn a child run, pass `runId` forward, and collect from a step when needed. |
|
|
55
55
|
| `inngest.send()` / event triggers | `start()` from your app boundary | Start workflows directly. |
|
|
56
56
|
| Retry configuration (`retries`) | `RetryableError`, `FatalError`, `maxRetries` | Retry logic lives at the step level. |
|
|
57
|
-
| `step.sendEvent()` | `
|
|
57
|
+
| `step.sendEvent()` | `start()` from the workflow or app boundary | Fan out explicitly, not through an event bus. |
|
|
58
58
|
| Realtime / `step.realtime.publish()` | `getWritable()` / `getWritable({ namespace })` | Named streams are the canonical way for clients to read workflow status. No database or `getRun()` polling required. |
|
|
59
59
|
|
|
60
60
|
## Translate your first workflow
|
|
@@ -169,20 +169,10 @@ Event matching disappears. A hook's token encodes the routing (for example, `ref
|
|
|
169
169
|
|
|
170
170
|
## Spawn a child workflow
|
|
171
171
|
|
|
172
|
-
`step.invoke()` splits into
|
|
172
|
+
`step.invoke()` splits into spawn and collect. In v5, call `start()` directly from the workflow to spawn the child. Wrap `getRun()` and `returnValue` access in a `"use step"` function when you need to collect the result. Returning the `Run` object from `start()` lets observability deep-link into the child run.
|
|
173
173
|
|
|
174
174
|
You can return either the full `Run` object (enables deep-linking) or just `run.runId` (simpler).
|
|
175
175
|
|
|
176
|
-
{/* @skip-typecheck: snippet without imports */}
|
|
177
|
-
```typescript title="workflow/workflows/parent.ts"
|
|
178
|
-
async function spawnChild(item: string) {
|
|
179
|
-
'use step';
|
|
180
|
-
return start(childWorkflow, [item]); // [!code highlight]
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
Await the result in a second step, then orchestrate both from the parent:
|
|
185
|
-
|
|
186
176
|
{/* @skip-typecheck: snippet without imports */}
|
|
187
177
|
```typescript title="workflow/workflows/parent.ts"
|
|
188
178
|
async function collectResult(runId: string) {
|
|
@@ -193,7 +183,7 @@ async function collectResult(runId: string) {
|
|
|
193
183
|
|
|
194
184
|
export async function parentWorkflow(item: string) {
|
|
195
185
|
'use workflow';
|
|
196
|
-
const child = await
|
|
186
|
+
const child = await start(childWorkflow, [item]); // [!code highlight]
|
|
197
187
|
return await collectResult(child.runId);
|
|
198
188
|
}
|
|
199
189
|
```
|
|
@@ -266,7 +256,7 @@ See [Errors and retries](/docs/foundations/errors-and-retries) for full retry do
|
|
|
266
256
|
|
|
267
257
|
- `step.waitForEvent(...)` → `createHook({ token })` + `await hook`. Resume it from an API route with `resumeHook(token, payload)`.
|
|
268
258
|
- `step.sleep(...)` → `sleep("5m")` from `workflow`.
|
|
269
|
-
- `step.invoke(child, { data })` →
|
|
259
|
+
- `step.invoke(child, { data })` → call `start(child, [data])` from the workflow, and optionally read its return value from a step with `getRun(run.runId).returnValue`.
|
|
270
260
|
|
|
271
261
|
### Step 5: Start runs from the app
|
|
272
262
|
|
|
@@ -301,8 +291,8 @@ Remove the `inngest` client, the `serve()` route, event schemas, and the Inngest
|
|
|
301
291
|
- Swap `step.sleep()` / `step.sleepUntil()` for `sleep()` from `workflow`.
|
|
302
292
|
- Swap `step.waitForEvent()` for `createHook()` (internal) or `createWebhook()` (HTTP).
|
|
303
293
|
- Model `waitForEvent` timeouts as `Promise.race()` between the hook and `sleep()`.
|
|
304
|
-
- Replace `step.invoke()` with `"use step"`
|
|
305
|
-
- Replace `step.sendEvent()` fan-out with `start()`
|
|
294
|
+
- Replace `step.invoke()` with direct `start()` calls and a `"use step"` wrapper around `getRun()` when collecting results.
|
|
295
|
+
- Replace `step.sendEvent()` fan-out with explicit `start()` calls.
|
|
306
296
|
- Remove the Inngest client, `serve()` handler, and event definitions.
|
|
307
297
|
- Push retry configuration down to step boundaries via `maxRetries`, `RetryableError`, and `FatalError`.
|
|
308
298
|
- Use `getStepMetadata().stepId` as the idempotency key for external side effects.
|
|
@@ -50,7 +50,7 @@ Migration removes infrastructure and collapses indirection. Business logic stays
|
|
|
50
50
|
| Signal | `createHook()` or `createWebhook()` | Use hooks for typed resume signals; webhooks for HTTP callbacks. |
|
|
51
51
|
| Query | `getWritable({ namespace: 'status' })` stream | Durably stream status updates from the workflow. Clients read from the stream instead of polling a database. |
|
|
52
52
|
| Update | `createHook()` + `resumeHook()` (one-way) | Temporal Updates return a value to the caller; hooks do not. If the Update returns data, either write the result to a named stream via `getWritable()` and have the caller read from it, or keep an HTTP read route that fetches the workflow's current state. |
|
|
53
|
-
| Child Workflow | `"use step"`
|
|
53
|
+
| Child Workflow | `start()` plus a `"use step"` wrapper around `getRun()` | Spawn a child run and return the `Run` object so observability can deep-link into child runs. |
|
|
54
54
|
| Activity retry policy | Step retries, `RetryableError`, `FatalError`, `maxRetries` | Retries live at the step boundary. |
|
|
55
55
|
| Event History | Workflow event log / run timeline | Same durable replay; built-in observability UI replaces Temporal Web. Search attributes and visibility APIs have no direct equivalent — filter by run status and timestamps instead. |
|
|
56
56
|
|
|
@@ -173,19 +173,14 @@ Temporal Queries expose in-memory workflow state on demand. In the Workflow SDK,
|
|
|
173
173
|
|
|
174
174
|
### Minimal translation
|
|
175
175
|
|
|
176
|
-
`start()`
|
|
176
|
+
In v5, call `start()` directly from the workflow to spawn a child run. Wrap `getRun()` and `returnValue` access in a `"use step"` function when you need to await the child result. Return the `Run` object (not a plain `runId` string) so workflow observability can deep-link into child runs.
|
|
177
177
|
|
|
178
178
|
```typescript title="workflow/workflows/parent.ts"
|
|
179
179
|
import { start } from 'workflow/api';
|
|
180
180
|
|
|
181
|
-
async function spawnChild(item: string) {
|
|
182
|
-
'use step'; // [!code highlight]
|
|
183
|
-
return start(childWorkflow, [item]); // [!code highlight]
|
|
184
|
-
}
|
|
185
|
-
|
|
186
181
|
export async function parentWorkflow(item: string) {
|
|
187
182
|
'use workflow';
|
|
188
|
-
const child = await
|
|
183
|
+
const child = await start(childWorkflow, [item]); // [!code highlight]
|
|
189
184
|
return { childRunId: child.runId };
|
|
190
185
|
}
|
|
191
186
|
```
|
|
@@ -204,7 +199,7 @@ async function collectResult(runId: string) {
|
|
|
204
199
|
}
|
|
205
200
|
```
|
|
206
201
|
|
|
207
|
-
Call
|
|
202
|
+
Call `start()` and then `collectResult()` from the parent in sequence: `const result = await collectResult(child.runId)`. To fan out, call `start()` inside a loop, then `Promise.all` the `collectResult` calls.
|
|
208
203
|
|
|
209
204
|
<Callout type="warn">
|
|
210
205
|
Activity retry policy moves to the step boundary. Use `maxRetries`, `RetryableError`, and `FatalError` on each step instead of a single workflow-wide retry block.
|
|
@@ -300,7 +295,7 @@ Remove the Worker process, `@temporalio/*` dependencies, and the Temporal Server
|
|
|
300
295
|
- **Event history archival.** Temporal archives histories to S3/GCS for long-term retention. Workflow SDK event logs are durable, but retention depends on the integration you are using. For example, see [Vercel Workflow Storage Retention](https://vercel.com/docs/workflows/pricing#storage-retention) for Vercel.
|
|
301
296
|
- **Per-activity timeouts (`startToCloseTimeout`, `scheduleToCloseTimeout`, `heartbeatTimeout`).** Implement deadlines inside the step with `AbortSignal.timeout(ms)`, or wrap the call in `Promise.race(step(), sleep(...))` from the workflow.
|
|
302
297
|
- **Rich retry policy (`initialInterval`, `backoffCoefficient`, `maximumInterval`, `nonRetryableErrorTypes`).** Only `maxRetries` is configurable. Classify retryability with `RetryableError`/`FatalError`; control delay between attempts via `new RetryableError(msg, { retryAfter: '5s' })`.
|
|
303
|
-
- **Workers + task queues.** Managed deployments replace workers; self-hosted deployments still need a `World` implementation (see [/docs/deploying/world](/docs/deploying/world)).
|
|
298
|
+
- **Workers + task queues.** Managed deployments replace workers; self-hosted deployments still need a `World` implementation (see [/docs/deploying/building-a-world](/docs/deploying/building-a-world)).
|
|
304
299
|
|
|
305
300
|
## Quick-start checklist
|
|
306
301
|
|
|
@@ -308,7 +303,7 @@ Remove the Worker process, `@temporalio/*` dependencies, and the Temporal Server
|
|
|
308
303
|
- Convert each Activity into a `"use step"` function.
|
|
309
304
|
- Remove Worker and Task Queue code. Start workflows from the app with `start()`.
|
|
310
305
|
- Replace Signals with `createHook()` or `createWebhook()` for HTTP callers.
|
|
311
|
-
-
|
|
306
|
+
- Use `start()` directly for child workflows, and wrap `getRun()` in a `"use step"` function when collecting results. Return the `Run` object from `start()` so observability can deep-link into child runs.
|
|
312
307
|
- Set retry policy per step with `maxRetries`, `RetryableError`, and `FatalError`.
|
|
313
308
|
- Use `getStepMetadata().stepId` as the idempotency key for external side effects.
|
|
314
309
|
- Stream status and progress from steps with `getWritable({ namespace: 'status' })`, and have clients read from the stream instead of polling.
|
|
@@ -48,7 +48,7 @@ Migration collapses the task abstraction into plain async functions. Business lo
|
|
|
48
48
|
| `logger` / `metadata.set` | `console` + `getWritable({ namespace: 'status' })` | Logs flow through the run timeline. Status writes go on a named stream. |
|
|
49
49
|
| `wait.for({ seconds \| minutes \| hours \| days })` / `wait.until({ date })` | `sleep()` | Import from `workflow`. |
|
|
50
50
|
| `wait.forToken({ timeout })` | `createHook()` + `Promise.race` with `sleep()` | Hooks carry a typed token. |
|
|
51
|
-
| `tasks.trigger()` / `triggerAndWait()` | `start()` and `getRun(runId).returnValue` |
|
|
51
|
+
| `tasks.trigger()` / `triggerAndWait()` | `start()` and `getRun(runId).returnValue` | Call `start()` directly; wrap `getRun()` collection in a `"use step"` function. |
|
|
52
52
|
| `batch.triggerAndWait()` | `Promise.all(runIds.map(collectResult))` | Fan out via standard concurrency. |
|
|
53
53
|
| `AbortTaskRunError` | `FatalError` | Stops retries immediately. |
|
|
54
54
|
| `retry.onThrow` / `retry.fetch` | `RetryableError`, `FatalError`, `maxRetries` | Retry count lives on the step via `myStep.maxRetries = N` (default 3). Control delay between attempts by throwing `new RetryableError(msg, { retryAfter: '5s' })` — there is no built-in exponential helper; compute the delay yourself based on `getStepMetadata().attempt` if you need one. |
|
|
@@ -180,23 +180,14 @@ A hook is an inbound write channel. The caller that knows the token resumes the
|
|
|
180
180
|
|
|
181
181
|
## Spawn a child workflow
|
|
182
182
|
|
|
183
|
-
`triggerAndWait()` splits into
|
|
183
|
+
`triggerAndWait()` splits into spawn and collect. In v5, call `start()` directly from the workflow to spawn the child. Wrap `getRun()` and `returnValue` access in a `"use step"` function when you need to collect the result.
|
|
184
184
|
|
|
185
185
|
You can return either the full `Run` object (enables deep-linking) or just `run.runId` (simpler). The runtime serializes `Run` to its `runId` in the event log either way.
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
import { start } from 'workflow/api';
|
|
189
|
-
|
|
190
|
-
async function spawnChild(item: string) {
|
|
191
|
-
'use step';
|
|
192
|
-
return start(childWorkflow, [item]); // [!code highlight]
|
|
193
|
-
}
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Await the result in a second step, then orchestrate both from the parent:
|
|
187
|
+
Await the result in a step, then orchestrate both from the parent:
|
|
197
188
|
|
|
198
189
|
```typescript title="workflow/workflows/parent.ts"
|
|
199
|
-
import { getRun } from 'workflow/api';
|
|
190
|
+
import { getRun, start } from 'workflow/api';
|
|
200
191
|
|
|
201
192
|
async function collectResult(runId: string) {
|
|
202
193
|
'use step';
|
|
@@ -206,12 +197,12 @@ async function collectResult(runId: string) {
|
|
|
206
197
|
|
|
207
198
|
export async function parentWorkflow(item: string) {
|
|
208
199
|
'use workflow';
|
|
209
|
-
const child = await
|
|
200
|
+
const child = await start(childWorkflow, [item]); // [!code highlight]
|
|
210
201
|
return await collectResult(child.runId);
|
|
211
202
|
}
|
|
212
203
|
```
|
|
213
204
|
|
|
214
|
-
To fan out, call `
|
|
205
|
+
To fan out, call `start()` inside a loop, then `Promise.all` the `collectResult` calls. That replaces `batch.triggerAndWait()`.
|
|
215
206
|
|
|
216
207
|
`Promise.all` rejects on first failure; use `Promise.allSettled` if you need batch-mode error tolerance similar to trigger.dev's `{ ok, output, error }` per-run result.
|
|
217
208
|
|
|
@@ -273,7 +264,7 @@ async function loadOrder(id: string) {
|
|
|
273
264
|
- `wait.for({ seconds | minutes | hours | days })` / `wait.until({ date })` → `sleep('5m')` or `sleep(date)` from `workflow`.
|
|
274
265
|
- `wait.forToken(token)` → `createHook({ token })` + `await`. Complete it with `resumeHook(token, payload)` from an API route.
|
|
275
266
|
- `wait.forToken({ timeout })` → `Promise.race([hook, sleep(timeout)])`.
|
|
276
|
-
- `triggerAndWait(payload)` →
|
|
267
|
+
- `triggerAndWait(payload)` → call `start(child, [payload])` from the workflow and return the `Run` object, then read the result with a step that calls `getRun(runId).returnValue`.
|
|
277
268
|
|
|
278
269
|
### Step 5: Start runs from the app
|
|
279
270
|
|
|
@@ -324,7 +315,7 @@ Throw `new RetryableError(msg, { retryAfter: '5s' })` to control delay between a
|
|
|
324
315
|
- Swap `wait.for` / `wait.until` for `sleep()` from `workflow`.
|
|
325
316
|
- Swap `wait.forToken` for `createHook()` (internal) or `createWebhook()` (HTTP).
|
|
326
317
|
- Model `wait.forToken` timeouts as `Promise.race()` between the hook and `sleep()`.
|
|
327
|
-
- Replace `triggerAndWait()` with `"use step"`
|
|
318
|
+
- Replace `triggerAndWait()` with direct `start()` calls and a `"use step"` wrapper around `getRun()` when collecting results.
|
|
328
319
|
- Replace `batch.triggerAndWait()` with `Promise.all` over the collected child `Run` handles.
|
|
329
320
|
- Move `schemaTask` validation to the call site; pass typed arguments into the workflow.
|
|
330
321
|
- Replace `AbortTaskRunError` with `FatalError`; model retries per step with `RetryableError` and `maxRetries`.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Attributes
|
|
3
|
+
description: Attach experimental metadata to workflow runs for observability.
|
|
4
|
+
type: reference
|
|
5
|
+
summary: Add string attributes to a workflow run.
|
|
6
|
+
prerequisites:
|
|
7
|
+
- /docs/foundations/workflows-and-steps
|
|
8
|
+
related:
|
|
9
|
+
- /docs/observability
|
|
10
|
+
- /docs/api-reference/workflow/experimental-set-attributes
|
|
11
|
+
- /docs/api-reference/workflow-errors/workflow-world-error
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<Callout type="warn">
|
|
15
|
+
This feature is experimental and may change before the stable attributes API is released.
|
|
16
|
+
</Callout>
|
|
17
|
+
|
|
18
|
+
[`experimental_setAttributes`](/docs/api-reference/workflow/experimental-set-attributes) attaches plaintext string metadata to the current workflow run. These attributes are displayed in observability CLI/UI.
|
|
19
|
+
In the future, you'll be able to search and filter runs by attributes.
|
|
20
|
+
|
|
21
|
+
You can also seed any attributes directly when starting a run:
|
|
22
|
+
|
|
23
|
+
{/* @skip-typecheck: abbreviated usage; orderWorkflow is defined below */}
|
|
24
|
+
```typescript lineNumbers
|
|
25
|
+
const run = await start(orderWorkflow, ["ord_123"], {
|
|
26
|
+
attributes: { source: "checkout" }, // [!code highlight]
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```typescript lineNumbers
|
|
31
|
+
import { experimental_setAttributes } from "workflow"
|
|
32
|
+
|
|
33
|
+
export async function orderWorkflow(orderId: string) {
|
|
34
|
+
"use workflow"
|
|
35
|
+
|
|
36
|
+
await experimental_setAttributes({ // [!code highlight]
|
|
37
|
+
phase: "received", // [!code highlight]
|
|
38
|
+
orderId, // [!code highlight]
|
|
39
|
+
}) // [!code highlight]
|
|
40
|
+
|
|
41
|
+
// ...work...
|
|
42
|
+
|
|
43
|
+
await experimental_setAttributes({ phase: "complete" }) // [!code highlight]
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
Call [`experimental_setAttributes`](/docs/api-reference/workflow/experimental-set-attributes) from a `"use workflow"` function or a `"use step"` function. Plain application code is not supported because there is no active workflow run to attach attributes to.
|
|
50
|
+
|
|
51
|
+
Values must be strings. Pass `undefined` to remove a key:
|
|
52
|
+
|
|
53
|
+
```typescript lineNumbers
|
|
54
|
+
import { experimental_setAttributes } from "workflow"
|
|
55
|
+
|
|
56
|
+
export async function cleanupAttributes() {
|
|
57
|
+
"use workflow"
|
|
58
|
+
|
|
59
|
+
await experimental_setAttributes({ staleKey: undefined }) // [!code highlight]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Attribute keys must be 1-256 characters, values must be strings up to 256 bytes, and each run can have up to 64 attributes. Keys that start with `$` are reserved for framework and library code.
|
|
64
|
+
|
|
65
|
+
## Viewing attributes
|
|
66
|
+
|
|
67
|
+
The run details panel in the observability UI shows the run's current attributes as key-value rows. Reserved `$`-prefixed keys are marked with a badge and sorted after user keys:
|
|
68
|
+
|
|
69
|
+

|
|
70
|
+
|
|
71
|
+
Each `experimental_setAttributes` call appears on the trace timeline as a diamond marker at the moment the attributes were written:
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
Expanding an `attr_set` event — in the run sidebar or the Events tab — shows the changed keys, removed keys, and whether the write came from the workflow body or a step (with the attempt number):
|
|
76
|
+
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+
## Experimental Behavior
|
|
80
|
+
|
|
81
|
+
While attributes are experimental:
|
|
82
|
+
|
|
83
|
+
- Attributes require a World implementing spec version 4 or later.
|
|
84
|
+
- Writes from workflow and step bodies append native `attr_set` events and immediately materialize `run.attributes`.
|
|
85
|
+
- Storage errors surface rather than being silently ignored: transient errors on workflow-body writes are retried, and a write the World rejects as invalid (for example, exceeding the per-run attribute cap across multiple calls) fails the run with the validation error.
|
|
86
|
+
- Step-body storage errors throw from `experimental_setAttributes` like any other step-side network write. Catch the error inside the step if the attribute is best-effort.
|
|
87
|
+
- Reading and querying attributes is not available yet. A query API is planned.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Observability
|
|
3
3
|
description: Inspect, monitor, and debug workflows through the CLI and Web UI with powerful observability tools.
|
|
4
|
-
type:
|
|
4
|
+
type: overview
|
|
5
5
|
summary: Inspect and debug workflow runs using the CLI and Web UI.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/foundations
|
|
@@ -42,6 +42,19 @@ npx workflow inspect runs --web
|
|
|
42
42
|
|
|
43
43
|

|
|
44
44
|
|
|
45
|
+
To share a link to a specific run without opening a browser, use the `--url`
|
|
46
|
+
flag. It prints the dashboard deep link to stdout and exits (no browser, no
|
|
47
|
+
local server) — useful for scripts, PR comments, or automation. Add `--json` to
|
|
48
|
+
get `{ "url": "..." }`.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Print the deep-link URL for a run (no browser, no server)
|
|
52
|
+
npx workflow inspect run <run_id> --url
|
|
53
|
+
|
|
54
|
+
# Vercel runs: add the backend (and --env preview for preview deployments)
|
|
55
|
+
npx workflow inspect run <run_id> --backend vercel --url
|
|
56
|
+
```
|
|
57
|
+
|
|
45
58
|
## Backends
|
|
46
59
|
|
|
47
60
|
The Workflow SDK CLI can inspect data from any [World](/docs/deploying). By default, it inspects data in your local development environment. For example, if you are using Next.js to develop workflows locally, the
|
|
@@ -63,3 +76,7 @@ npx workflow inspect runs --backend vercel
|
|
|
63
76
|
```
|
|
64
77
|
|
|
65
78
|
When deployed to Vercel, workflow data is [encrypted end-to-end](/docs/how-it-works/encryption). Encrypted fields display as locked placeholders until you choose to decrypt them using the **Decrypt** button in the web UI or the `--decrypt` flag in the CLI.
|
|
79
|
+
|
|
80
|
+
## More Observability Features
|
|
81
|
+
|
|
82
|
+
<AutoCards />
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tracing
|
|
3
|
+
description: Distributed tracing with OpenTelemetry for workflow runs, steps, and queue deliveries.
|
|
4
|
+
type: guide
|
|
5
|
+
summary: Trace workflow execution end to end with OpenTelemetry.
|
|
6
|
+
prerequisites:
|
|
7
|
+
- /docs/foundations/workflows-and-steps
|
|
8
|
+
related:
|
|
9
|
+
- /docs/observability
|
|
10
|
+
- /docs/observability/attributes
|
|
11
|
+
- /docs/how-it-works/event-sourcing
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
The Workflow SDK is instrumented with [OpenTelemetry](https://opentelemetry.io) out of the box. It emits spans for workflow starts, every workflow and step invocation, and the HTTP calls it makes to the workflow backend — and it propagates trace context across queue deliveries so a run remains traceable end to end.
|
|
15
|
+
|
|
16
|
+
The SDK only depends on the OpenTelemetry **API**, never on an SDK or exporter. If your application does not register an OpenTelemetry SDK, all tracing code is a silent no-op with no overhead and no behavior change.
|
|
17
|
+
|
|
18
|
+
## Enabling tracing
|
|
19
|
+
|
|
20
|
+
Register any OpenTelemetry Node SDK in your application. On Vercel with Next.js, the simplest setup is [`@vercel/otel`](https://vercel.com/docs/observability/otel-overview) in `instrumentation.ts`:
|
|
21
|
+
|
|
22
|
+
```typescript title="instrumentation.ts" lineNumbers
|
|
23
|
+
import { registerOTel } from "@vercel/otel"
|
|
24
|
+
|
|
25
|
+
export function register() {
|
|
26
|
+
registerOTel({ serviceName: "my-app" })
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
No workflow-specific configuration is required. As soon as a tracer provider and propagator are registered, the SDK's spans, context propagation, and span links activate automatically.
|
|
31
|
+
|
|
32
|
+
<Callout>
|
|
33
|
+
`@opentelemetry/api` is an **optional peer dependency**. An OpenTelemetry SDK such as `@vercel/otel` normally pulls it in transitively, but installing it directly (`npm i @opentelemetry/api`) guarantees it is present in your build — particularly for bundled or serverless targets where the SDK's tracing is inlined at build time. If it can't be resolved, tracing is a silent no-op.
|
|
34
|
+
</Callout>
|
|
35
|
+
|
|
36
|
+
## Spans
|
|
37
|
+
|
|
38
|
+
| Span name | Kind | Emitted when |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `workflow.start <name>` | internal | `start()` is called in your application code |
|
|
41
|
+
| `workflow.execute <name>` | consumer (root) | a queue delivery invokes the workflow — replay, orchestration, and inline steps run under it |
|
|
42
|
+
| `step.execute <name>` | internal (inline) / consumer + root (queue-delivered) | a step function executes |
|
|
43
|
+
| `http <method>` | client | the SDK calls the workflow backend (event reads/writes) |
|
|
44
|
+
| `workflow.stream.write` | client | a stream chunk (or the stream close) is flushed to the backend |
|
|
45
|
+
| `workflow.stream.read.connect` | client | a live stream read opens; the span covers dispatch → response headers (network connect) |
|
|
46
|
+
| `workflow.stream.read` | client | a live stream read receives its first chunk; the span's duration is the end-to-end time-to-first-chunk (see `workflow.stream.read.ttfc_ms`) |
|
|
47
|
+
|
|
48
|
+
`<name>` is the short function name (for example `processOrder`); the full machine name, including the source module, is available in the `workflow.name` / `step.name` attributes.
|
|
49
|
+
|
|
50
|
+
Stream spans are emitted by the SDK's world backend on the client that writes or reads the stream, and (like all SDK spans) are no-ops when no OpenTelemetry SDK is registered. The `workflow.stream.read` span only appears once the first non-empty chunk arrives.
|
|
51
|
+
|
|
52
|
+
## Key attributes
|
|
53
|
+
|
|
54
|
+
| Attribute | Description |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| `workflow.run.id` | The run ID (`wrun_...`). Present on every workflow and step span — the primary key for finding all spans of a run. |
|
|
57
|
+
| `workflow.name` | The workflow function name. |
|
|
58
|
+
| `workflow.trace.mode` | The active trace mode (`linked` or `continuous`). |
|
|
59
|
+
| `workflow.trace.propagated` | Whether the invocation received trace context from the queue message. |
|
|
60
|
+
| `workflow.queue.overhead_ms` | Time between the message being enqueued and the handler starting — queue dwell plus any cold start. |
|
|
61
|
+
| `workflow.stream.name` | The stream name, on stream write/read spans. |
|
|
62
|
+
| `workflow.stream.operation` | The stream operation: `write`, `write_multi`, `close`, or `read`. |
|
|
63
|
+
| `workflow.stream.write.chunk_rtt` | Time between emissions of a chunk to the wire, and receiving the `ack` message for that chunk. |
|
|
64
|
+
| `workflow.stream.read.ttfc_ms` | Time between opening a read connection and observing and receiving the first chunk back. |
|
|
65
|
+
|
|
66
|
+
## Trace shape: one trace per invocation
|
|
67
|
+
|
|
68
|
+
A single workflow run can span hours or days across many separate function invocations: every step completion, `sleep()` wake-up, and retry is a new queue delivery. Stitching all of that into one trace produces giant, slow-loading traces that most tracing backends truncate.
|
|
69
|
+
|
|
70
|
+
Instead, the SDK creates **one bounded trace per invocation**. Each `workflow.execute` (or background `step.execute`) span starts a new trace root and attaches two **span links**:
|
|
71
|
+
|
|
72
|
+
- a link to the **enqueue site** — the span that queued the message which triggered this invocation, and
|
|
73
|
+
- a link to the **run origin** — the trace in which `start()` was originally called.
|
|
74
|
+
|
|
75
|
+
A span link is OpenTelemetry's relationship for "causally related, but in a different trace." It is the standard pattern for asynchronous messaging, where producing and consuming a message can be separated by arbitrary time.
|
|
76
|
+
|
|
77
|
+
```mermaid
|
|
78
|
+
flowchart LR
|
|
79
|
+
O["start() request trace"]
|
|
80
|
+
A["invocation 1"]
|
|
81
|
+
B["invocation 2"]
|
|
82
|
+
C["invocation 3 ..."]
|
|
83
|
+
A -. "link" .-> O
|
|
84
|
+
B -. "link" .-> O
|
|
85
|
+
C -. "link" .-> O
|
|
86
|
+
B -. "link" .-> A
|
|
87
|
+
C -. "link" .-> B
|
|
88
|
+
|
|
89
|
+
style O fill:#a78bfa,stroke:#8b5cf6,color:#000
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Each invocation links back to the trace that enqueued it and to the run origin.
|
|
93
|
+
|
|
94
|
+
To see a whole run, query by attribute rather than by trace ID — for example `workflow.run.id = wrun_...` in your tracing backend — or follow the span links between invocation traces.
|
|
95
|
+
|
|
96
|
+
## Trace modes
|
|
97
|
+
|
|
98
|
+
The `WORKFLOW_TRACE_MODE` environment variable controls the shape:
|
|
99
|
+
|
|
100
|
+
| Mode | Behavior |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| `linked` (default) | Each invocation is its own trace root with span links to the enqueue site and the run origin. Traces stay small; sampling is decided per invocation. |
|
|
103
|
+
| `continuous` | The run-origin context becomes the **parent** of every invocation, so the entire run shares one trace ID. |
|
|
104
|
+
|
|
105
|
+
<Callout type="warn">
|
|
106
|
+
This is a behavior change from v4, which always used `continuous`-style tracing. If you have dashboards or queries that assume one trace ID per run, either update them to use `workflow.run.id` and span links, or set `WORKFLOW_TRACE_MODE=continuous` to restore the previous shape. Note that in `linked` mode each invocation root makes its own sampling decision, and the number of root spans increases to one per invocation.
|
|
107
|
+
</Callout>
|
|
108
|
+
|
|
109
|
+
## Context propagation
|
|
110
|
+
|
|
111
|
+
When tracing is enabled, the SDK propagates [W3C Trace Context](https://www.w3.org/TR/trace-context/) on its outbound calls:
|
|
112
|
+
|
|
113
|
+
- **Backend requests** carry `traceparent`, `tracestate`, and `baggage` headers, so backend spans can join your trace.
|
|
114
|
+
- **Queue messages** carry the run-origin trace context in the message payload, and the queue re-delivers the producer's context to the workflow handler, where it becomes the enqueue-site span link.
|
|
115
|
+
- **Baggage** carries `workflow.run_id` and `workflow.name` entries during workflow execution, allowing downstream services you call from steps to tag their own telemetry with the run ID.
|
|
116
|
+
|
|
117
|
+
<Callout>
|
|
118
|
+
Baggage entries set by your application are propagated as a `baggage` HTTP header on the SDK's backend requests, like any other OpenTelemetry-instrumented HTTP call. Avoid placing sensitive values in baggage.
|
|
119
|
+
</Callout>
|
package/docs/testing/index.mdx
CHANGED
|
@@ -109,7 +109,7 @@ That's it. The plugin automatically:
|
|
|
109
109
|
|
|
110
110
|
1. Transforms `"use workflow"` and `"use step"` directives via SWC
|
|
111
111
|
2. Builds workflow and step bundles before tests run
|
|
112
|
-
3. Sets up an in-process workflow runtime using a fresh [Local World](/
|
|
112
|
+
3. Sets up an in-process workflow runtime using a fresh [Local World](/worlds/local) instance in each test worker — all workflow data is cleared automatically between test files for full isolation
|
|
113
113
|
|
|
114
114
|
<Callout type="info">
|
|
115
115
|
Use a separate Vitest configuration and a distinct file naming convention (e.g. `*.integration.test.ts`) to keep unit tests and integration tests separate. Unit tests run with a standard Vitest config without the workflow plugin, while integration tests use the config above.
|
|
@@ -117,7 +117,7 @@ Use a separate Vitest configuration and a distinct file naming convention (e.g.
|
|
|
117
117
|
|
|
118
118
|
### Writing Integration Tests
|
|
119
119
|
|
|
120
|
-
Use [`start()`](/docs/api-reference/workflow-api/start) to trigger a workflow and [`run.returnValue`](/docs/api-reference/workflow-api/start#
|
|
120
|
+
Use [`start()`](/docs/api-reference/workflow-api/start) to trigger a workflow and [`run.returnValue`](/docs/api-reference/workflow-api/start#returns) to get the result. `returnValue` is a promise that blocks until the workflow completes (or throws if it fails):
|
|
121
121
|
|
|
122
122
|
```typescript title="workflows/calculate.integration.test.ts" lineNumbers
|
|
123
123
|
import { describe, it, expect } from "vitest";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "workflow",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.30",
|
|
4
4
|
"description": "Workflow SDK - Build durable, resilient, and observable workflows",
|
|
5
5
|
"main": "dist/typescript-plugin.cjs",
|
|
6
6
|
"type": "module",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
".": {
|
|
30
30
|
"types": "./dist/index.d.ts",
|
|
31
31
|
"workflow": "./dist/workflow.js",
|
|
32
|
+
"node": "./dist/index.js",
|
|
32
33
|
"require": "./dist/typescript-plugin.cjs",
|
|
33
34
|
"default": "./dist/index.js"
|
|
34
35
|
},
|
|
@@ -56,18 +57,18 @@
|
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
59
|
"ms": "2.1.3",
|
|
59
|
-
"@workflow/astro": "5.0.0-beta.
|
|
60
|
-
"@workflow/cli": "5.0.0-beta.
|
|
61
|
-
"@workflow/
|
|
62
|
-
"@workflow/
|
|
63
|
-
"@workflow/
|
|
64
|
-
"@workflow/
|
|
65
|
-
"@workflow/
|
|
66
|
-
"@workflow/nest": "5.0.0-beta.
|
|
67
|
-
"@workflow/nitro": "5.0.0-beta.
|
|
68
|
-
"@workflow/nuxt": "5.0.0-beta.
|
|
69
|
-
"@workflow/sveltekit": "5.0.0-beta.
|
|
70
|
-
"@workflow/rollup": "5.0.0-beta.
|
|
60
|
+
"@workflow/astro": "5.0.0-beta.30",
|
|
61
|
+
"@workflow/cli": "5.0.0-beta.30",
|
|
62
|
+
"@workflow/core": "5.0.0-beta.30",
|
|
63
|
+
"@workflow/errors": "5.0.0-beta.10",
|
|
64
|
+
"@workflow/typescript-plugin": "5.0.0-beta.5",
|
|
65
|
+
"@workflow/utils": "5.0.0-beta.6",
|
|
66
|
+
"@workflow/next": "5.0.0-beta.30",
|
|
67
|
+
"@workflow/nest": "5.0.0-beta.30",
|
|
68
|
+
"@workflow/nitro": "5.0.0-beta.30",
|
|
69
|
+
"@workflow/nuxt": "5.0.0-beta.30",
|
|
70
|
+
"@workflow/sveltekit": "5.0.0-beta.30",
|
|
71
|
+
"@workflow/rollup": "5.0.0-beta.30"
|
|
71
72
|
},
|
|
72
73
|
"devDependencies": {
|
|
73
74
|
"@types/ms": "2.1.0",
|