@workflow/core 5.0.0-beta.42 → 5.0.0-beta.44
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/capabilities.d.ts +4 -4
- package/dist/capabilities.js +5 -5
- package/dist/capture-stack.d.ts +1 -1
- package/dist/capture-stack.js +2 -2
- package/dist/class-serialization.d.ts +8 -8
- package/dist/class-serialization.js +9 -9
- package/dist/classify-error.js +5 -5
- package/dist/context-violation-error.d.ts +5 -5
- package/dist/context-violation-error.d.ts.map +1 -1
- package/dist/context-violation-error.js +5 -5
- package/dist/create-hook.d.ts +10 -6
- package/dist/create-hook.d.ts.map +1 -1
- package/dist/create-hook.js +1 -1
- package/dist/define-hook.js +2 -2
- package/dist/describe-error.d.ts +7 -7
- package/dist/describe-error.js +8 -8
- package/dist/encryption.d.ts +5 -5
- package/dist/encryption.js +7 -7
- package/dist/events-consumer.d.ts +19 -7
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +33 -12
- package/dist/flushable-stream.d.ts +4 -4
- package/dist/flushable-stream.js +12 -12
- package/dist/global.d.ts +1 -1
- package/dist/global.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/log-format.d.ts +2 -2
- package/dist/log-format.js +5 -5
- package/dist/logger.js +4 -4
- package/dist/private.d.ts +39 -64
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +294 -48
- package/dist/replay-payload-cache.d.ts +1 -1
- package/dist/replay-payload-cache.js +4 -4
- package/dist/runtime/compute-instance.d.ts +4 -3
- package/dist/runtime/compute-instance.d.ts.map +1 -1
- package/dist/runtime/compute-instance.js +5 -4
- package/dist/runtime/constants.d.ts +46 -19
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +76 -38
- package/dist/runtime/count-step-started-events.d.ts +7 -7
- package/dist/runtime/count-step-started-events.js +4 -4
- package/dist/runtime/deployment-guard.d.ts +7 -7
- package/dist/runtime/deployment-guard.js +8 -8
- package/dist/runtime/get-port-lazy.d.ts +2 -2
- package/dist/runtime/get-port-lazy.d.ts.map +1 -1
- package/dist/runtime/get-port-lazy.js +37 -30
- package/dist/runtime/get-world-lazy.d.ts +2 -2
- package/dist/runtime/get-world-lazy.js +3 -3
- package/dist/runtime/helpers.d.ts +18 -18
- package/dist/runtime/helpers.js +27 -27
- package/dist/runtime/quickjs-entrypoint.d.ts +23 -10
- package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -1
- package/dist/runtime/quickjs-entrypoint.js +200 -81
- package/dist/runtime/quickjs-runtime.d.ts +31 -15
- package/dist/runtime/quickjs-runtime.d.ts.map +1 -1
- package/dist/runtime/quickjs-runtime.js +126 -77
- package/dist/runtime/quickjs-serde.d.ts +10 -10
- package/dist/runtime/quickjs-serde.js +20 -20
- package/dist/runtime/replay-budget.d.ts +4 -4
- package/dist/runtime/replay-budget.js +5 -5
- package/dist/runtime/replay-recovery-reporter.d.ts +1 -1
- package/dist/runtime/replay-recovery-reporter.js +2 -2
- package/dist/runtime/resume-hook.d.ts +2 -2
- package/dist/runtime/resume-hook.js +27 -27
- package/dist/runtime/resume-latency.d.ts +25 -25
- package/dist/runtime/resume-latency.d.ts.map +1 -1
- package/dist/runtime/resume-latency.js +4 -4
- package/dist/runtime/run-id-time.d.ts +2 -2
- package/dist/runtime/run-id-time.js +5 -5
- package/dist/runtime/run.d.ts +21 -4
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +154 -35
- package/dist/runtime/runs.d.ts +4 -4
- package/dist/runtime/runs.js +2 -2
- package/dist/runtime/start.d.ts +3 -3
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +27 -23
- package/dist/runtime/step-executor.d.ts +59 -11
- package/dist/runtime/step-executor.d.ts.map +1 -1
- package/dist/runtime/step-executor.js +116 -42
- package/dist/runtime/step-latency.d.ts +20 -14
- package/dist/runtime/step-latency.d.ts.map +1 -1
- package/dist/runtime/step-latency.js +13 -11
- package/dist/runtime/step-ownership.d.ts +6 -6
- package/dist/runtime/step-ownership.js +8 -8
- package/dist/runtime/step-single-flight.d.ts +1 -1
- package/dist/runtime/step-single-flight.d.ts.map +1 -1
- package/dist/runtime/step-single-flight.js +17 -11
- package/dist/runtime/suspension-handler.d.ts +99 -7
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +678 -57
- package/dist/runtime/unserializable-step.d.ts +34 -0
- package/dist/runtime/unserializable-step.d.ts.map +1 -0
- package/dist/runtime/unserializable-step.js +52 -0
- package/dist/runtime/vm-mode.d.ts +1 -1
- package/dist/runtime/vm-mode.js +2 -2
- package/dist/runtime/wait-continuation.d.ts +31 -9
- package/dist/runtime/wait-continuation.d.ts.map +1 -1
- package/dist/runtime/wait-continuation.js +44 -13
- package/dist/runtime/wait-until.d.ts +1 -1
- package/dist/runtime/wait-until.js +2 -2
- package/dist/runtime/world-compatibility.d.ts +20 -9
- package/dist/runtime/world-compatibility.d.ts.map +1 -1
- package/dist/runtime/world-compatibility.js +24 -13
- package/dist/runtime/world-init.d.ts +5 -5
- package/dist/runtime/world-init.js +6 -6
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +13 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +417 -213
- package/dist/sealed-box.d.ts +7 -7
- package/dist/sealed-box.js +15 -15
- package/dist/serialization/client.js +2 -2
- package/dist/serialization/codec-devalue-vm.d.ts +1 -1
- package/dist/serialization/codec-devalue-vm.js +4 -4
- package/dist/serialization/codec-devalue.d.ts +1 -1
- package/dist/serialization/codec-devalue.js +2 -2
- package/dist/serialization/codec.d.ts +4 -4
- package/dist/serialization/codec.js +2 -2
- package/dist/serialization/compression.d.ts +12 -11
- package/dist/serialization/compression.d.ts.map +1 -1
- package/dist/serialization/compression.js +16 -15
- package/dist/serialization/encryption.d.ts +7 -7
- package/dist/serialization/encryption.d.ts.map +1 -1
- package/dist/serialization/encryption.js +8 -8
- package/dist/serialization/errors.js +2 -2
- package/dist/serialization/format.d.ts +6 -6
- package/dist/serialization/format.js +7 -7
- package/dist/serialization/hardened.d.ts +18 -18
- package/dist/serialization/hardened.d.ts.map +1 -1
- package/dist/serialization/hardened.js +41 -32
- package/dist/serialization/index.d.ts +1 -1
- package/dist/serialization/index.js +2 -2
- package/dist/serialization/reducers/class-vm.d.ts +1 -1
- package/dist/serialization/reducers/class-vm.js +2 -2
- package/dist/serialization/reducers/class.js +2 -2
- package/dist/serialization/reducers/common-vm.js +12 -12
- package/dist/serialization/reducers/common.js +12 -12
- package/dist/serialization/reducers/step-function-vm.d.ts +1 -1
- package/dist/serialization/reducers/step-function-vm.js +2 -2
- package/dist/serialization/reducers/step-function.js +2 -2
- package/dist/serialization/step.js +2 -2
- package/dist/serialization/types.d.ts +5 -5
- package/dist/serialization/types.js +2 -2
- package/dist/serialization/workflow-vm.d.ts +1 -1
- package/dist/serialization/workflow-vm.d.ts.map +1 -1
- package/dist/serialization/workflow-vm.js +13 -10
- package/dist/serialization-format.d.ts +11 -11
- package/dist/serialization-format.d.ts.map +1 -1
- package/dist/serialization-format.js +29 -23
- package/dist/serialization.d.ts +20 -12
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +141 -99
- package/dist/set-attributes.js +2 -2
- package/dist/source-map.d.ts +1 -1
- package/dist/source-map.d.ts.map +1 -1
- package/dist/source-map.js +18 -12
- package/dist/step/context-storage.d.ts +5 -5
- package/dist/step/context-storage.js +1 -1
- package/dist/step/writable-stream.d.ts +3 -3
- package/dist/step/writable-stream.js +7 -7
- package/dist/step.js +12 -12
- package/dist/symbols.d.ts +2 -2
- package/dist/symbols.js +3 -3
- package/dist/telemetry/semantic-conventions.d.ts +21 -13
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +21 -15
- package/dist/telemetry.d.ts +9 -3
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +40 -10
- package/dist/test-support/orchestrator-context.d.ts.map +1 -1
- package/dist/test-support/orchestrator-context.js +12 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/dist/vm/index.js +4 -4
- package/dist/vm/script-cache.d.ts.map +1 -1
- package/dist/vm/script-cache.js +23 -17
- package/dist/vm/uint8array-base64.js +1 -1
- package/dist/workflow/abort-controller.d.ts +1 -1
- package/dist/workflow/abort-controller.js +12 -12
- package/dist/workflow/create-hook.js +3 -3
- package/dist/workflow/get-workflow-metadata.js +2 -2
- package/dist/workflow/hook.js +18 -18
- package/dist/workflow/set-attributes.d.ts +1 -1
- package/dist/workflow/set-attributes.js +2 -2
- package/dist/workflow/sleep.js +2 -2
- package/dist/workflow/world-init-stub.d.ts +1 -1
- package/dist/workflow/world-init-stub.js +2 -2
- package/dist/workflow.d.ts +2 -2
- package/dist/workflow.js +36 -14
- package/docs/api-reference/create-hook.mdx +15 -15
- package/docs/api-reference/create-webhook.mdx +15 -15
- package/docs/api-reference/define-hook.mdx +10 -10
- package/docs/api-reference/fatal-error.mdx +2 -2
- package/docs/api-reference/fetch.mdx +7 -7
- package/docs/api-reference/get-step-metadata.mdx +2 -2
- package/docs/api-reference/get-workflow-metadata.mdx +3 -3
- package/docs/api-reference/get-writable.mdx +7 -7
- package/docs/api-reference/index.mdx +1 -1
- package/docs/api-reference/retryable-error.mdx +1 -1
- package/docs/api-reference/set-attributes.mdx +2 -2
- package/docs/api-reference/sleep.mdx +3 -3
- package/docs/foundations/cancellation.mdx +31 -31
- package/docs/foundations/errors-and-retries.mdx +42 -11
- package/docs/foundations/hooks.mdx +37 -37
- package/docs/foundations/idempotency.mdx +9 -9
- package/docs/foundations/serialization.mdx +21 -22
- package/docs/foundations/starting-workflows.mdx +36 -37
- package/docs/foundations/streaming.mdx +68 -39
- package/docs/foundations/versioning.mdx +3 -3
- package/docs/foundations/workflows-and-steps.mdx +9 -9
- package/docs/how-it-works/cancellation.mdx +62 -62
- package/docs/how-it-works/code-transform.mdx +66 -54
- package/docs/how-it-works/encryption.mdx +25 -21
- package/docs/how-it-works/event-sourcing.mdx +84 -28
- package/docs/how-it-works/framework-integrations.mdx +12 -12
- package/docs/how-it-works/understanding-directives.mdx +21 -21
- package/package.json +7 -7
|
@@ -15,11 +15,11 @@ All function arguments and return values passed between workflow and step functi
|
|
|
15
15
|
The serialization system ensures that all data persists correctly across workflow suspensions and resumptions, enabling durable execution.
|
|
16
16
|
</Callout>
|
|
17
17
|
|
|
18
|
-
## Supported
|
|
18
|
+
## Supported serializable types
|
|
19
19
|
|
|
20
20
|
The following types can be serialized and passed through workflow functions:
|
|
21
21
|
|
|
22
|
-
**Standard JSON
|
|
22
|
+
**Standard JSON types:**
|
|
23
23
|
|
|
24
24
|
- `string`
|
|
25
25
|
- `number`
|
|
@@ -28,7 +28,7 @@ The following types can be serialized and passed through workflow functions:
|
|
|
28
28
|
- Arrays of serializable values
|
|
29
29
|
- Objects with string keys and serializable values
|
|
30
30
|
|
|
31
|
-
**Extended
|
|
31
|
+
**Extended types:**
|
|
32
32
|
|
|
33
33
|
- `undefined`
|
|
34
34
|
- `bigint`
|
|
@@ -58,7 +58,7 @@ These types have special handling and are explained in detail in the sections be
|
|
|
58
58
|
- `AbortController`
|
|
59
59
|
- `AbortSignal`
|
|
60
60
|
|
|
61
|
-
## Pass-by-
|
|
61
|
+
## Pass-by-value semantics
|
|
62
62
|
|
|
63
63
|
**Parameters are passed by value, not by reference.** Steps receive deserialized copies of data. Mutations inside a step won't affect the original in the workflow.
|
|
64
64
|
|
|
@@ -81,7 +81,7 @@ async function updateUserStep(user: { id: string; name: string; email: string })
|
|
|
81
81
|
}
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
**Correct
|
|
84
|
+
**Correct, return the modified data:**
|
|
85
85
|
|
|
86
86
|
```typescript title="workflows/correct-mutation.ts" lineNumbers
|
|
87
87
|
export async function updateUserWorkflow(userId: string) {
|
|
@@ -100,7 +100,7 @@ async function updateUserStep(user: { id: string; name: string; email: string })
|
|
|
100
100
|
}
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
**Custom
|
|
103
|
+
**Custom classes:**
|
|
104
104
|
|
|
105
105
|
- Class instances that implement [`WORKFLOW_SERIALIZE` and `WORKFLOW_DESERIALIZE`](#custom-class-serialization)
|
|
106
106
|
|
|
@@ -110,7 +110,7 @@ async function updateUserStep(user: { id: string; name: string; email: string })
|
|
|
110
110
|
|
|
111
111
|
For complete information about using streams in workflows, including patterns for AI streaming, file processing, and progress updates, see the [Streaming Guide](/docs/foundations/streaming).
|
|
112
112
|
|
|
113
|
-
## Request &
|
|
113
|
+
## Request & response
|
|
114
114
|
|
|
115
115
|
The Web API [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) APIs are supported by the serialization system,
|
|
116
116
|
and can be passed around between workflow and step functions similarly to other data types.
|
|
@@ -140,7 +140,7 @@ export async function handleWebhookWorkflow() {
|
|
|
140
140
|
}
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
### Using `fetch` in
|
|
143
|
+
### Using `fetch` in workflows
|
|
144
144
|
|
|
145
145
|
Because `Request` and `Response` are serializable, Workflow SDK provides a `fetch` function that can be used directly in workflow functions:
|
|
146
146
|
|
|
@@ -158,7 +158,7 @@ export async function apiWorkflow() {
|
|
|
158
158
|
}
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
The
|
|
161
|
+
The `fetch` implementation from `workflow` is a step function that wraps the standard `fetch`:
|
|
162
162
|
|
|
163
163
|
```typescript title="Implementation" lineNumbers
|
|
164
164
|
export async function fetch(...args: Parameters<typeof globalThis.fetch>) {
|
|
@@ -202,11 +202,11 @@ async function fetchData(signal: AbortSignal) {
|
|
|
202
202
|
|
|
203
203
|
For usage patterns including timeouts, parallel cancellation, user-triggered cancellation, and run cancellation, see the [Cancellation Guide](/docs/foundations/cancellation). For details on the hook and stream backing that makes this work, see [How Cancellation Works](/docs/how-it-works/cancellation).
|
|
204
204
|
|
|
205
|
-
## Custom
|
|
205
|
+
## Custom class serialization
|
|
206
206
|
|
|
207
207
|
By default, custom class instances cannot be serialized because the serialization system doesn't know how to reconstruct them. You can make your classes serializable by implementing two static methods using special symbols from the `@workflow/serde` package.
|
|
208
208
|
|
|
209
|
-
### Basic
|
|
209
|
+
### Basic example
|
|
210
210
|
|
|
211
211
|
{/* @expect-error:2351 */}
|
|
212
212
|
|
|
@@ -256,13 +256,13 @@ async function doublePoint(point: Point) {
|
|
|
256
256
|
}
|
|
257
257
|
```
|
|
258
258
|
|
|
259
|
-
### How
|
|
259
|
+
### How it works
|
|
260
260
|
|
|
261
261
|
1. **`WORKFLOW_SERIALIZE`**: A static method that receives a class instance and returns serializable data (primitives, plain objects, arrays, etc.)
|
|
262
262
|
|
|
263
263
|
2. **`WORKFLOW_DESERIALIZE`**: A static method that receives the serialized data and returns a new class instance
|
|
264
264
|
|
|
265
|
-
3. **Automatic Registration**: The SWC compiler plugin automatically detects classes that implement these symbols and registers them for serialization. Each class receives a deterministic `classId` derived from its file path and class name, and is registered into the global `Symbol.for("workflow-class-registry")` registry at build time
|
|
265
|
+
3. **Automatic Registration**: The SWC compiler plugin automatically detects classes that implement these symbols and registers them for serialization. Each class receives a deterministic `classId` derived from its file path and class name, and is registered into the global `Symbol.for("workflow-class-registry")` registry at build time. No manual registration step is required
|
|
266
266
|
|
|
267
267
|
### Requirements
|
|
268
268
|
|
|
@@ -279,12 +279,12 @@ The `WORKFLOW_SERIALIZE` and `WORKFLOW_DESERIALIZE` methods run inside the workf
|
|
|
279
279
|
- No non-deterministic operations (like `Math.random()` or `Date.now()`)
|
|
280
280
|
- No external network calls
|
|
281
281
|
|
|
282
|
-
Keep these methods
|
|
282
|
+
Keep these methods focused on data transformation only.
|
|
283
283
|
</Callout>
|
|
284
284
|
|
|
285
|
-
### Instance
|
|
285
|
+
### Instance methods as steps
|
|
286
286
|
|
|
287
|
-
In practice, many classes have methods that need Node.js APIs, perform network calls, or interact with databases
|
|
287
|
+
In practice, many classes have methods that need Node.js APIs, perform network calls, or interact with databases, operations that are not allowed in the `"use workflow"` execution context. You can make these methods workflow-compatible by adding `"use step"` to them. The SWC compiler will strip the method bodies from the workflow bundle and replace them with proxy functions that invoke the method as a step, with full Node.js runtime access. The `this` context (the class instance) is automatically serialized and deserialized across the workflow/step boundary.
|
|
288
288
|
|
|
289
289
|
This requires the class to implement `WORKFLOW_SERIALIZE` and `WORKFLOW_DESERIALIZE`, so that the instance can be passed to the step execution context.
|
|
290
290
|
|
|
@@ -301,7 +301,7 @@ class Order {
|
|
|
301
301
|
public createdAt: Date
|
|
302
302
|
) {}
|
|
303
303
|
|
|
304
|
-
// Custom serialization
|
|
304
|
+
// Custom serialization: data must be serializable types
|
|
305
305
|
static [WORKFLOW_SERIALIZE](instance: Order) { // [!code highlight]
|
|
306
306
|
return { // [!code highlight]
|
|
307
307
|
id: instance.id, // [!code highlight]
|
|
@@ -329,7 +329,7 @@ class Order {
|
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
// Instance methods with "use step" run as step functions
|
|
332
|
-
// with full Node.js access
|
|
332
|
+
// with full Node.js access; `this` is automatically serialized
|
|
333
333
|
async save(): Promise<void> {
|
|
334
334
|
"use step"; // [!code highlight]
|
|
335
335
|
await db.orders.insert({ // [!code highlight]
|
|
@@ -355,7 +355,7 @@ class Order {
|
|
|
355
355
|
}
|
|
356
356
|
```
|
|
357
357
|
|
|
358
|
-
The class can then be used naturally inside a workflow function. Instance methods marked with `"use step"` are each executed as a step
|
|
358
|
+
The class can then be used naturally inside a workflow function. Instance methods marked with `"use step"` are each executed as a step, with automatic caching, retry semantics, and full Node.js runtime access. Methods _without_ `"use step"` run directly in the workflow context, so they must follow the same constraints as workflow functions:
|
|
359
359
|
|
|
360
360
|
{/* @expect-error:2693 */}
|
|
361
361
|
|
|
@@ -369,7 +369,7 @@ export async function processOrderWorkflow(
|
|
|
369
369
|
|
|
370
370
|
const order = new Order(orderId, items, new Date()); // [!code highlight]
|
|
371
371
|
|
|
372
|
-
// Runs in the workflow context
|
|
372
|
+
// Runs in the workflow context; no "use step" needed
|
|
373
373
|
const itemCount = order.total(); // [!code highlight]
|
|
374
374
|
|
|
375
375
|
// Each "use step" instance method call runs as a separate step
|
|
@@ -380,7 +380,7 @@ export async function processOrderWorkflow(
|
|
|
380
380
|
}
|
|
381
381
|
```
|
|
382
382
|
|
|
383
|
-
|
|
383
|
+
[Pass-by-value semantics](#pass-by-value-semantics) also apply to the `this` context of `"use step"` instance methods. Modifying instance properties inside a step method will not affect the original instance in the workflow. If you need to update instance state, return `this` from the step method and re-assign the variable in the workflow:
|
|
384
384
|
|
|
385
385
|
{/* @expect-error:2351 */}
|
|
386
386
|
|
|
@@ -408,4 +408,3 @@ export async function processOrderWorkflow() {
|
|
|
408
408
|
order = await order.addItem("Widget", 3); // [!code highlight]
|
|
409
409
|
}
|
|
410
410
|
```
|
|
411
|
-
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Starting
|
|
2
|
+
title: Starting workflows
|
|
3
3
|
description: Trigger workflow execution with the start() function and track progress with Run objects.
|
|
4
4
|
type: guide
|
|
5
5
|
summary: Trigger workflows and track their execution using the start() function.
|
|
@@ -9,11 +9,11 @@ related:
|
|
|
9
9
|
- /docs/api-reference/workflow-api/start
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
After you define a workflow function, use the `start()` function from `workflow/api` to trigger it. The function enqueues a new workflow run and returns a `Run` object for tracking its progress.
|
|
13
13
|
|
|
14
|
-
## The `start()`
|
|
14
|
+
## The `start()` function
|
|
15
15
|
|
|
16
|
-
The [`start()`](/docs/api-reference/workflow-api/start) function
|
|
16
|
+
The [`start()`](/docs/api-reference/workflow-api/start) function programmatically triggers workflow executions from runtime contexts such as API routes, Server Actions, or other server-side code. In v5, you can also call `start()` inside a workflow function to spawn a child run or continue work in a new run.
|
|
17
17
|
|
|
18
18
|
```typescript lineNumbers
|
|
19
19
|
import { start } from "workflow/api";
|
|
@@ -32,20 +32,21 @@ export async function POST(request: Request) {
|
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
**Key
|
|
35
|
+
**Key points:**
|
|
36
36
|
|
|
37
|
-
- `start()` returns immediately after enqueuing the workflow
|
|
37
|
+
- `start()` returns immediately after enqueuing the workflow. It doesn't wait for completion
|
|
38
38
|
- The first argument is your workflow function
|
|
39
39
|
- The second argument is an array of arguments to pass to the workflow (optional if the workflow takes no arguments)
|
|
40
40
|
- All arguments must be [serializable](/docs/foundations/serialization)
|
|
41
|
+
- On Worlds with a regional dimension, the optional `region` option pins the new run's storage, queuing, and streams to a specific region. See [Multi-region on the Vercel World](/worlds/vercel#multi-region)
|
|
41
42
|
|
|
42
|
-
**Learn more**: [`start()` API
|
|
43
|
+
**Learn more**: [`start()` API reference](/docs/api-reference/workflow-api/start)
|
|
43
44
|
|
|
44
45
|
<Callout type="info">
|
|
45
46
|
For parent-child workflow patterns, see [Workflow Composition](/cookbook/common-patterns/workflow-composition). For long-lived workflows that intentionally hand off to newer deployments with `deploymentId: "latest"`, see [Versioning](/docs/foundations/versioning).
|
|
46
47
|
</Callout>
|
|
47
48
|
|
|
48
|
-
## The `Run`
|
|
49
|
+
## The `Run` object
|
|
49
50
|
|
|
50
51
|
When you call `start()`, it returns a [`Run`](/docs/api-reference/workflow-api/start#returns) object that provides access to the workflow's status and results.
|
|
51
52
|
|
|
@@ -65,22 +66,22 @@ const status = await run.status; // "running" | "completed" | "failed"
|
|
|
65
66
|
const result = await run.returnValue;
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
**Key
|
|
69
|
+
**Key properties:**
|
|
69
70
|
|
|
70
|
-
- `runId
|
|
71
|
-
- `status
|
|
72
|
-
- `returnValue
|
|
73
|
-
- `readable`
|
|
71
|
+
- `runId`: Unique identifier for this workflow run
|
|
72
|
+
- `status`: Current status of the workflow (async)
|
|
73
|
+
- `returnValue`: The value returned by the workflow function (async, blocks until completion)
|
|
74
|
+
- `readable`: `ReadableStream` for streaming updates from the workflow
|
|
74
75
|
|
|
75
76
|
<Callout type="info">
|
|
76
|
-
Most `Run` properties are async getters that return promises.
|
|
77
|
+
Most `Run` properties are async getters that return promises. `await` them to get their values. For a complete list of properties and methods, see the API reference below.
|
|
77
78
|
</Callout>
|
|
78
79
|
|
|
79
|
-
**Learn more**: [`Run` API
|
|
80
|
+
**Learn more**: [`Run` API reference](/docs/api-reference/workflow-api/start#returns)
|
|
80
81
|
|
|
81
|
-
## Common
|
|
82
|
+
## Common patterns
|
|
82
83
|
|
|
83
|
-
### Starting
|
|
84
|
+
### Starting workflows from workflow functions
|
|
84
85
|
|
|
85
86
|
You can also call `start()` directly inside workflow functions to spawn child workflows. For choosing between this and awaiting a workflow function directly, see [Workflow Composition](/cookbook/common-patterns/workflow-composition).
|
|
86
87
|
|
|
@@ -93,25 +94,25 @@ export async function parentWorkflow(inputValue: number) {
|
|
|
93
94
|
|
|
94
95
|
const childRun = await start(childWorkflow, [inputValue]); // [!code highlight]
|
|
95
96
|
|
|
96
|
-
// childRun is a full Run object
|
|
97
|
+
// childRun is a full Run object. Use it like normal.
|
|
97
98
|
const childResult = await childRun.returnValue;
|
|
98
99
|
return { childRunId: childRun.runId, childResult };
|
|
99
100
|
}
|
|
100
101
|
```
|
|
101
102
|
|
|
102
|
-
When `start()`
|
|
103
|
+
When you call `start()` inside a workflow function, it automatically executes through an internal step to maintain deterministic replay. The returned `Run` object works as it does outside workflows. Properties such as `.runId`, `.status`, and `.returnValue`, and methods such as `.cancel()`, are all available. Each property access or method call executes as a separate step.
|
|
103
104
|
|
|
104
105
|
<Callout type="info">
|
|
105
106
|
Inside workflow functions, each `Run` property access (e.g., `run.status`, `run.returnValue`) triggers a workflow step. This means each access is recorded in the event log and replayed deterministically.
|
|
106
107
|
</Callout>
|
|
107
108
|
|
|
108
109
|
<Callout type="warn">
|
|
109
|
-
Awaiting `returnValue` polls the child run every second, and the polling step holds its worker slot open
|
|
110
|
+
Awaiting `returnValue` polls the child run every second, and the polling step holds its worker slot open until the child finishes. Size worker-based Worlds to cover the peak number of these polls in flight. If the child workflow is long-running, spawn it without awaiting `returnValue` and have it resume a [hook](/docs/foundations/hooks) when it completes. See the [`startAndWait()` pattern](/cookbook/advanced/child-workflows).
|
|
110
111
|
</Callout>
|
|
111
112
|
|
|
112
|
-
### Fire and
|
|
113
|
+
### Fire and forget
|
|
113
114
|
|
|
114
|
-
|
|
115
|
+
Start a workflow and immediately return to let it execute in the background:
|
|
115
116
|
|
|
116
117
|
```typescript lineNumbers
|
|
117
118
|
import { start } from "workflow/api";
|
|
@@ -129,7 +130,7 @@ export async function POST(request: Request) {
|
|
|
129
130
|
}
|
|
130
131
|
```
|
|
131
132
|
|
|
132
|
-
### Wait for
|
|
133
|
+
### Wait for completion
|
|
133
134
|
|
|
134
135
|
If you need to wait for the workflow to complete before responding:
|
|
135
136
|
|
|
@@ -148,12 +149,12 @@ export async function POST(request: Request) {
|
|
|
148
149
|
```
|
|
149
150
|
|
|
150
151
|
<Callout type="warn">
|
|
151
|
-
|
|
152
|
+
Waiting for `returnValue` can cause your API route to time out if the workflow takes a long time.
|
|
152
153
|
</Callout>
|
|
153
154
|
|
|
154
|
-
### Stream
|
|
155
|
+
### Stream updates to client
|
|
155
156
|
|
|
156
|
-
Stream
|
|
157
|
+
Stream updates from your workflow as it executes without waiting for completion:
|
|
157
158
|
|
|
158
159
|
```typescript lineNumbers
|
|
159
160
|
import { start } from "workflow/api";
|
|
@@ -211,12 +212,12 @@ async function streamContentToClient(
|
|
|
211
212
|
```
|
|
212
213
|
|
|
213
214
|
<Callout type="info">
|
|
214
|
-
|
|
215
|
+
Use streams to show users real-time progress from AI workflows or intermediate results from long-running processes.
|
|
215
216
|
</Callout>
|
|
216
217
|
|
|
217
|
-
**Learn more**: [Streaming in
|
|
218
|
+
**Learn more**: [Streaming in workflows](/docs/foundations/serialization#streaming)
|
|
218
219
|
|
|
219
|
-
### Check
|
|
220
|
+
### Check status later
|
|
220
221
|
|
|
221
222
|
You can retrieve a workflow run later using its `runId` with [`getRun()`](/docs/api-reference/workflow-api/get-run):
|
|
222
223
|
|
|
@@ -242,9 +243,9 @@ export async function GET(request: Request) {
|
|
|
242
243
|
}
|
|
243
244
|
```
|
|
244
245
|
|
|
245
|
-
### Recursive and
|
|
246
|
+
### Recursive and repeating workflows
|
|
246
247
|
|
|
247
|
-
A workflow can start a new instance of itself. This
|
|
248
|
+
A workflow can start a new instance of itself. This pattern prevents a single long-running workflow from accumulating too many events. Large event logs are slower to replay, more expensive to store, and harder to inspect in the UI. Breaking work into smaller runs that chain together keeps each run lean.
|
|
248
249
|
|
|
249
250
|
```typescript lineNumbers
|
|
250
251
|
import { start } from "workflow/api";
|
|
@@ -264,7 +265,7 @@ export async function processQueue(cursor?: string) {
|
|
|
264
265
|
}
|
|
265
266
|
```
|
|
266
267
|
|
|
267
|
-
This pattern also enables **repeating cron-like workflows**. A workflow can complete its work, sleep, and then schedule a new instance of itself
|
|
268
|
+
This pattern also enables **repeating cron-like workflows**. A workflow can complete its work, sleep, and then schedule a new instance of itself. This creates an indefinite chain without allowing any single run to grow too large:
|
|
268
269
|
|
|
269
270
|
```typescript lineNumbers
|
|
270
271
|
import { sleep } from "workflow";
|
|
@@ -286,10 +287,8 @@ export async function syncDashboard() {
|
|
|
286
287
|
|
|
287
288
|
By default a chained run starts on the same deployment as its parent. For workflows that chain over long periods, pass [`deploymentId: "latest"`](/docs/api-reference/workflow-api/start#using-deploymentid-latest) so the next run picks up new code. [Versioning](/docs/foundations/versioning#self-upgrading-workflows) covers this pattern in full, including how the serialized state acts as the migration boundary between versions.
|
|
288
289
|
|
|
289
|
-
## Next
|
|
290
|
-
|
|
291
|
-
Now that you understand how to start workflows and track their execution:
|
|
290
|
+
## Next steps
|
|
292
291
|
|
|
293
292
|
- Browse the [Cookbook](/cookbook) for copy-paste recipes covering composition, scheduling, timeouts, and more
|
|
294
|
-
- Explore [Errors
|
|
295
|
-
- Check the [`start()` API
|
|
293
|
+
- Explore [Errors and retrying](/docs/foundations/errors-and-retries) to handle failures
|
|
294
|
+
- Check the [`start()` API reference](/docs/api-reference/workflow-api/start) for complete details
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Streaming
|
|
3
|
-
description: Stream data in real
|
|
3
|
+
description: Stream data in real time to clients for progress updates and incremental content delivery.
|
|
4
4
|
type: conceptual
|
|
5
|
-
summary: Stream
|
|
5
|
+
summary: Stream data to clients in real time without waiting for workflow completion.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/foundations/workflows-and-steps
|
|
8
8
|
related:
|
|
@@ -10,9 +10,9 @@ related:
|
|
|
10
10
|
- /docs/ai/resumable-streams
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
Workflows can stream data in real
|
|
13
|
+
Workflows can stream data to clients in real time without waiting for the entire workflow to complete. Clients can receive progress updates, AI-generated content, log messages, and other incremental data as workflows execute.
|
|
14
14
|
|
|
15
|
-
## Getting
|
|
15
|
+
## Getting started with `getWritable()`
|
|
16
16
|
|
|
17
17
|
Every workflow run has a default writable stream that steps can write to using [`getWritable()`](/docs/api-reference/workflow/get-writable). Data written to this stream becomes immediately available to clients consuming the workflow's output.
|
|
18
18
|
|
|
@@ -38,7 +38,7 @@ export async function simpleStreamingWorkflow() {
|
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
### Consuming the
|
|
41
|
+
### Consuming the stream
|
|
42
42
|
|
|
43
43
|
Use the `Run` object's `readable` property to consume the stream from your API route:
|
|
44
44
|
|
|
@@ -58,7 +58,31 @@ export async function POST() {
|
|
|
58
58
|
|
|
59
59
|
When a client makes a request to this endpoint, they'll receive each message as it's written, without waiting for the workflow to complete.
|
|
60
60
|
|
|
61
|
-
###
|
|
61
|
+
### Avoiding function timeouts after client disconnects
|
|
62
|
+
|
|
63
|
+
On Vercel, `run.readable` and `run.getReadable()` reconnect to Workflow's stream storage while the workflow is still running. By default, a client disconnect does not terminate the Vercel Function serving the stream. If a user closes the page or stops the request, the function can therefore keep reconnecting until it reaches its maximum duration and fails with `FUNCTION_INVOCATION_TIMEOUT`.
|
|
64
|
+
|
|
65
|
+
For streaming routes using the Node.js runtime, opt in to [request cancellation](https://vercel.com/docs/functions/functions-api-reference#enable-cancellation) in `vercel.json`:
|
|
66
|
+
|
|
67
|
+
```json filename="vercel.json"
|
|
68
|
+
{
|
|
69
|
+
"functions": {
|
|
70
|
+
"app/api/stream/route.ts": {
|
|
71
|
+
"supportsCancellation": true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Replace the function path with the path or glob for your streaming route. When the downstream client disconnects, Vercel terminates the matching function invocation instead of leaving its stream reader running. The workflow run and its durable stream continue independently, so the client can reconnect through another route invocation later.
|
|
78
|
+
|
|
79
|
+
<Callout type="warn">
|
|
80
|
+
Cancellation applies to every function matching the configured path or glob, even if the route does not listen to `request.signal`. Any other work in that invocation which is not wrapped in [`waitUntil`](https://vercel.com/docs/functions/functions-api-reference/vercel-functions-package#waituntil) or [`after`](https://nextjs.org/docs/app/api-reference/functions/after) can be lost. Only enable it for routes that are safe to terminate when their client disconnects.
|
|
81
|
+
</Callout>
|
|
82
|
+
|
|
83
|
+
This setting prevents abandoned stream readers from consuming the rest of a function invocation. It does not extend the function's maximum duration. An actively connected streaming response can still reach the configured limit, at which point the client should reconnect to the durable stream.
|
|
84
|
+
|
|
85
|
+
### Resuming streams from a specific point
|
|
62
86
|
|
|
63
87
|
Use `run.getReadable({ startIndex })` to resume a stream from a specific position. This is useful for reconnecting after timeouts or network interruptions:
|
|
64
88
|
|
|
@@ -85,7 +109,7 @@ export async function GET(
|
|
|
85
109
|
}
|
|
86
110
|
```
|
|
87
111
|
|
|
88
|
-
|
|
112
|
+
Clients can reconnect and continue receiving data from where they left off instead of restarting from the beginning.
|
|
89
113
|
|
|
90
114
|
`startIndex` also supports **negative values** to read relative to the end of the stream. For example, `startIndex: -5` starts 5 chunks before the current end. This is useful when you want to show the most recent output without reading the entire stream history.
|
|
91
115
|
|
|
@@ -103,31 +127,32 @@ If the absolute value exceeds the total number of chunks, reading starts from th
|
|
|
103
127
|
Because streams are live and continue receiving chunks, negative `startIndex` values resolve to different absolute positions on each call. Accurate pagination over a live stream requires cursor-based access, which is not yet supported. Keep this in mind when building clients that paginate over stream data.
|
|
104
128
|
</Callout>
|
|
105
129
|
|
|
106
|
-
## Streams as
|
|
130
|
+
## Streams as data types
|
|
107
131
|
|
|
108
|
-
[`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) and [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) are standard Web Streams API types that Workflow SDK makes serializable.
|
|
132
|
+
[`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) and [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) are standard Web Streams API types that Workflow SDK makes serializable. Workflow SDK lets you pass these standard types between functions while maintaining their streaming capabilities.
|
|
109
133
|
|
|
110
134
|
Unlike regular values that are fully serialized to the [event log](/docs/how-it-works/event-sourcing), streams maintain their streaming capabilities when passed between functions.
|
|
111
135
|
|
|
112
136
|
**Key properties:**
|
|
137
|
+
|
|
113
138
|
- Stream references can be passed between workflow and step functions
|
|
114
139
|
- Stream data flows directly without being stored in the event log
|
|
115
140
|
- Streams preserve their state across workflow suspension points
|
|
116
141
|
|
|
117
142
|
<Callout type="info">
|
|
118
|
-
**How
|
|
143
|
+
**How streams persist across workflow suspensions**
|
|
119
144
|
|
|
120
|
-
|
|
145
|
+
Persistent, resumable storage from the World implementation lets Workflow SDK streams maintain their state when workflows suspend and resume:
|
|
121
146
|
|
|
122
147
|
- **Vercel deployments**: Streams are backed by a performant Redis-based stream
|
|
123
148
|
- **Local development**: Stream chunks are stored in the filesystem
|
|
124
149
|
</Callout>
|
|
125
150
|
|
|
126
|
-
### Passing
|
|
151
|
+
### Passing streams as arguments
|
|
127
152
|
|
|
128
|
-
|
|
153
|
+
Because streams are serializable data types, you don't need to use [`getWritable()`](/docs/api-reference/workflow/get-writable). You can pass your own streams as arguments from outside a workflow into steps.
|
|
129
154
|
|
|
130
|
-
|
|
155
|
+
The following example passes a request body stream through a workflow to a step that processes it:
|
|
131
156
|
|
|
132
157
|
```typescript title="app/api/upload/route.ts" lineNumbers
|
|
133
158
|
import { start } from "workflow/api";
|
|
@@ -167,15 +192,15 @@ async function processInputStream(input: ReadableStream<Uint8Array>) {
|
|
|
167
192
|
}
|
|
168
193
|
```
|
|
169
194
|
|
|
170
|
-
## Important
|
|
195
|
+
## Important limitation
|
|
171
196
|
|
|
172
197
|
<Callout type="info">
|
|
173
|
-
**Streams
|
|
198
|
+
**Streams cannot be used directly in workflow context**
|
|
174
199
|
|
|
175
200
|
You cannot read from or write to streams directly within a workflow function. All stream operations must happen in step functions.
|
|
176
201
|
</Callout>
|
|
177
202
|
|
|
178
|
-
Workflow functions must be deterministic to support replay.
|
|
203
|
+
Workflow functions must be deterministic to support replay. Streams bypass the [event log](/docs/how-it-works/event-sourcing) for performance, so reading stream data in a workflow would break determinism because each replay could see different data. Requiring all stream operations to happen in steps ensures consistent behavior.
|
|
179
204
|
|
|
180
205
|
For more on determinism and replay, see [Workflows and Steps](/docs/foundations/workflows-and-steps).
|
|
181
206
|
|
|
@@ -214,7 +239,7 @@ async function writeToStream(data: string) {
|
|
|
214
239
|
}
|
|
215
240
|
```
|
|
216
241
|
|
|
217
|
-
## Namespaced
|
|
242
|
+
## Namespaced streams
|
|
218
243
|
|
|
219
244
|
Use `getWritable({ namespace: 'name' })` to create multiple independent streams for different types of data. This is useful when you want to separate logs, metrics, data outputs, or other distinct channels.
|
|
220
245
|
|
|
@@ -264,7 +289,7 @@ export async function multiStreamWorkflow() {
|
|
|
264
289
|
}
|
|
265
290
|
```
|
|
266
291
|
|
|
267
|
-
### Consuming
|
|
292
|
+
### Consuming namespaced streams
|
|
268
293
|
|
|
269
294
|
Use `run.getReadable({ namespace: 'name' })` to access specific streams:
|
|
270
295
|
|
|
@@ -289,9 +314,9 @@ export async function POST(request: Request) {
|
|
|
289
314
|
}
|
|
290
315
|
```
|
|
291
316
|
|
|
292
|
-
## Common
|
|
317
|
+
## Common patterns
|
|
293
318
|
|
|
294
|
-
### Progress
|
|
319
|
+
### Progress updates for long-running tasks
|
|
295
320
|
|
|
296
321
|
Send incremental progress updates to keep users informed during lengthy workflows:
|
|
297
322
|
|
|
@@ -345,7 +370,7 @@ export async function batchProcessingWorkflow(items: string[]) {
|
|
|
345
370
|
}
|
|
346
371
|
```
|
|
347
372
|
|
|
348
|
-
### Streaming AI
|
|
373
|
+
### Streaming AI responses with `WorkflowAgent`
|
|
349
374
|
|
|
350
375
|
Stream AI-generated content using AI SDK's [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent) from `@ai-sdk/workflow`. The agent writes `ModelCallStreamPart` chunks to the workflow stream, and route handlers convert them to UI message chunks with `createModelCallToUIChunkTransform()` before returning the response:
|
|
351
376
|
|
|
@@ -406,7 +431,7 @@ export async function POST(request: Request) {
|
|
|
406
431
|
For the full agent API and migration notes, see the [`WorkflowAgent` documentation](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent).
|
|
407
432
|
</Callout>
|
|
408
433
|
|
|
409
|
-
### Streaming
|
|
434
|
+
### Streaming between steps
|
|
410
435
|
|
|
411
436
|
One step produces a stream and another step consumes it:
|
|
412
437
|
|
|
@@ -447,7 +472,7 @@ async function consumeData(readable: ReadableStream<number>) {
|
|
|
447
472
|
}
|
|
448
473
|
```
|
|
449
474
|
|
|
450
|
-
### Processing
|
|
475
|
+
### Processing large files without memory overhead
|
|
451
476
|
|
|
452
477
|
Process large files by streaming chunks through transformation steps:
|
|
453
478
|
|
|
@@ -488,7 +513,11 @@ async function uploadResult(stream: ReadableStream<Uint8Array>) {
|
|
|
488
513
|
}
|
|
489
514
|
```
|
|
490
515
|
|
|
491
|
-
## Best
|
|
516
|
+
## Best practices
|
|
517
|
+
|
|
518
|
+
**Batching and first-chunk latency:**
|
|
519
|
+
|
|
520
|
+
Writes are flushed immediately by default. The leading chunk of an idle stream dispatches as soon as it is written, and chunks arriving while a flush is in flight coalesce into the next batch. If you write bursts of many tiny chunks and prefer fewer round trips over first-chunk latency, set a group-commit window with the World's `streamFlushIntervalMs` option or the `WORKFLOW_STREAM_FLUSH_INTERVAL_MS` environment variable. See [Worlds configuration](/docs/configuration/worlds#streamflushintervalms).
|
|
492
521
|
|
|
493
522
|
**Release locks properly:**
|
|
494
523
|
|
|
@@ -506,7 +535,7 @@ Stream locks acquired in a step only apply within that step, not across other st
|
|
|
506
535
|
</Callout>
|
|
507
536
|
|
|
508
537
|
<Callout type="warn">
|
|
509
|
-
If a lock is not released, the
|
|
538
|
+
If a lock is not released, the invocation that ran the step cannot terminate. Even though the step returns and the workflow continues, the underlying request remains active until it times out and wastes compute resources.
|
|
510
539
|
</Callout>
|
|
511
540
|
|
|
512
541
|
**Close streams when done:**
|
|
@@ -532,7 +561,7 @@ const writer = writable.getWriter();
|
|
|
532
561
|
await writer.write({ /* typed data */ });
|
|
533
562
|
```
|
|
534
563
|
|
|
535
|
-
## Stream
|
|
564
|
+
## Stream failures
|
|
536
565
|
|
|
537
566
|
When a step returns a stream, the step is considered successful once it returns, even if the stream later encounters an error. The workflow won't automatically retry the step. The consumer of the stream must handle errors gracefully. For more on retry behavior, see [Errors and Retries](/docs/foundations/errors-and-retries).
|
|
538
567
|
|
|
@@ -575,17 +604,17 @@ export async function streamErrorWorkflow() {
|
|
|
575
604
|
```
|
|
576
605
|
|
|
577
606
|
<Callout type="info">
|
|
578
|
-
Stream errors don't trigger automatic retries for the producer step. Design your stream consumers to handle errors
|
|
607
|
+
Stream errors don't trigger automatic retries for the producer step. Design your stream consumers to handle errors. Because the stream is already in an errored state, retrying the consumer won't help. Use `FatalError` to fail the workflow immediately.
|
|
579
608
|
</Callout>
|
|
580
609
|
|
|
581
|
-
## Related
|
|
582
|
-
|
|
583
|
-
- [`getWritable()` API
|
|
584
|
-
- [`sleep()` API
|
|
585
|
-
- [`start()` API
|
|
586
|
-
- [`getRun()` API
|
|
587
|
-
- [world.streams](/docs/api-reference/workflow-runtime/world/streams)
|
|
588
|
-
- [WorkflowAgent](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent)
|
|
589
|
-
- [Errors and
|
|
590
|
-
- [Serialization](/docs/foundations/serialization)
|
|
591
|
-
- [Workflows and
|
|
610
|
+
## Related documentation
|
|
611
|
+
|
|
612
|
+
- [`getWritable()` API reference](/docs/api-reference/workflow/get-writable): Get the workflow's writable stream
|
|
613
|
+
- [`sleep()` API reference](/docs/api-reference/workflow/sleep): Pause workflow execution for a duration
|
|
614
|
+
- [`start()` API reference](/docs/api-reference/workflow-api/start): Start workflows and access the `Run` object
|
|
615
|
+
- [`getRun()` API reference](/docs/api-reference/workflow-api/get-run): Retrieve runs and their streams later
|
|
616
|
+
- [`world.streams`](/docs/api-reference/workflow-runtime/world/streams): Use low-level stream read, write, and close operations through the World SDK
|
|
617
|
+
- [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent): Build AI agents with durable, resumable streaming support
|
|
618
|
+
- [Errors and retries](/docs/foundations/errors-and-retries): Understand error handling and retry behavior
|
|
619
|
+
- [Serialization](/docs/foundations/serialization): Understand which data types you can pass in workflows
|
|
620
|
+
- [Workflows and steps](/docs/foundations/workflows-and-steps): Learn the core concepts of workflow execution
|
|
@@ -75,7 +75,7 @@ Sometimes you deploy because the old code had a bug. The safest fix is usually e
|
|
|
75
75
|
3. Cancel the old runs if they are still running.
|
|
76
76
|
4. Rerun them on the latest deployment with the same inputs.
|
|
77
77
|
|
|
78
|
-
This keeps the version boundary visible. The old run ends as
|
|
78
|
+
This keeps the version boundary visible. The old run ends as canceled or failed, and the replacement run starts fresh on the fixed deployment. This is a good fit for one-off, ad-hoc upgrades where you explicitly opt in to moving affected runs onto a new version.
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
81
|
# Inspect affected runs and copy the exact workflowName value.
|
|
@@ -121,9 +121,9 @@ export async function POST(request: Request) {
|
|
|
121
121
|
|
|
122
122
|
## Self upgrading workflows
|
|
123
123
|
|
|
124
|
-
Some workflows are expected to run for
|
|
124
|
+
Some workflows are expected to run for long periods. Scheduled loops, recurring jobs, agents, and chat sessions often should not stay on one deployment forever.
|
|
125
125
|
|
|
126
|
-
Model those as a sequence of runs. Each run does a bounded piece of work, then starts the next run on the latest deployment and exits. This is similar to `continueAsNew` in other durable execution systems, but
|
|
126
|
+
Model those as a sequence of runs. Each run does a bounded piece of work, then starts the next run on the latest deployment and exits. This is similar to `continueAsNew` in other durable execution systems, but Workflow SDK uses [explicit recursion through `start()`](/cookbook/common-patterns/workflow-composition).
|
|
127
127
|
|
|
128
128
|
```typescript title="workflows/daily-digest.ts" lineNumbers
|
|
129
129
|
import { sleep } from "workflow";
|