workflow 5.0.0-beta.9 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -23
- package/dist/api-workflow.d.ts +3 -1
- package/dist/api-workflow.d.ts.map +1 -1
- package/dist/api-workflow.js +2 -1
- package/dist/api.d.ts +5 -4
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +6 -7
- 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 +4 -4
- package/dist/internal/builtins.js +6 -6
- package/dist/internal/errors.d.ts +1 -1
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +2 -2
- package/dist/nest-builder.d.ts +2 -0
- package/dist/nest-builder.d.ts.map +1 -0
- package/dist/nest-builder.js +2 -0
- package/dist/nest-vercel-builder.d.ts +2 -0
- package/dist/nest-vercel-builder.d.ts.map +1 -0
- package/dist/nest-vercel-builder.js +2 -0
- package/dist/runtime.d.ts +2 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +4 -1
- package/docs/advanced/dynamic-workflows.mdx +224 -0
- package/docs/ai/chat-session-modeling.mdx +176 -422
- package/docs/ai/defining-tools.mdx +6 -7
- package/docs/ai/human-in-the-loop.mdx +11 -11
- package/docs/ai/index.mdx +67 -72
- package/docs/ai/message-queueing.mdx +71 -110
- package/docs/ai/meta.json +1 -0
- package/docs/ai/resumable-streams.mdx +40 -28
- package/docs/ai/sleep-and-delays.mdx +10 -10
- package/docs/ai/streaming-updates-from-tools.mdx +6 -6
- package/docs/api-reference/index.mdx +25 -1
- package/docs/api-reference/meta.json +8 -0
- package/docs/api-reference/vitest/index.mdx +68 -15
- package/docs/api-reference/workflow/create-hook.mdx +166 -10
- package/docs/api-reference/workflow/create-webhook.mdx +16 -15
- package/docs/api-reference/workflow/define-hook.mdx +37 -33
- package/docs/api-reference/workflow/fatal-error.mdx +30 -8
- package/docs/api-reference/workflow/fetch.mdx +14 -10
- package/docs/api-reference/workflow/get-step-metadata.mdx +2 -2
- package/docs/api-reference/workflow/get-workflow-metadata.mdx +3 -3
- package/docs/api-reference/workflow/get-writable.mdx +7 -7
- package/docs/api-reference/workflow/index.mdx +3 -3
- package/docs/api-reference/workflow/retryable-error.mdx +1 -1
- package/docs/api-reference/workflow/set-attributes.mdx +63 -0
- package/docs/api-reference/workflow/sleep.mdx +4 -4
- package/docs/api-reference/workflow-ai/durable-agent.mdx +63 -101
- package/docs/api-reference/workflow-ai/index.mdx +5 -5
- package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +67 -24
- package/docs/api-reference/workflow-api/get-hook-by-token.mdx +28 -12
- package/docs/api-reference/workflow-api/get-run.mdx +43 -8
- package/docs/api-reference/workflow-api/index.mdx +8 -9
- package/docs/api-reference/workflow-api/register-lifecycle-hooks.mdx +87 -0
- package/docs/api-reference/workflow-api/resume-hook.mdx +73 -12
- package/docs/api-reference/workflow-api/resume-webhook.mdx +11 -9
- package/docs/api-reference/workflow-api/start.mdx +107 -12
- 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/entity-conflict-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
- package/docs/api-reference/workflow-errors/hook-force-claimed-error.mdx +70 -0
- package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +8 -8
- package/docs/api-reference/workflow-errors/index.mdx +91 -0
- package/docs/api-reference/workflow-errors/meta.json +7 -0
- package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +68 -0
- package/docs/api-reference/workflow-errors/run-expired-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
- package/docs/api-reference/workflow-errors/step-not-registered-error.mdx +5 -5
- package/docs/api-reference/workflow-errors/throttle-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/too-early-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/workflow-error.mdx +52 -0
- package/docs/api-reference/workflow-errors/workflow-not-registered-error.mdx +5 -6
- package/docs/api-reference/workflow-errors/workflow-run-cancelled-error.mdx +13 -6
- package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +12 -5
- package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
- package/docs/api-reference/workflow-errors/workflow-run-not-found-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
- package/docs/api-reference/workflow-errors/workflow-world-error.mdx +8 -8
- package/docs/api-reference/workflow-globals.mdx +15 -11
- package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +37 -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 +46 -0
- package/docs/api-reference/workflow-nest/workflow-module.mdx +134 -0
- package/docs/api-reference/workflow-next/with-workflow.mdx +39 -17
- 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 +62 -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 +11 -14
- package/docs/api-reference/workflow-runtime/health-check.mdx +51 -0
- package/docs/api-reference/workflow-runtime/index.mdx +41 -0
- package/docs/api-reference/workflow-runtime/meta.json +12 -0
- package/docs/api-reference/workflow-runtime/set-world.mdx +51 -0
- package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +43 -0
- package/docs/api-reference/workflow-runtime/world/analytics.mdx +315 -0
- package/docs/api-reference/workflow-runtime/world/index.mdx +60 -0
- package/docs/api-reference/workflow-runtime/world/meta.json +4 -0
- package/docs/api-reference/workflow-runtime/world/queue.mdx +88 -0
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/storage.mdx +104 -35
- package/docs/api-reference/{workflow-api → workflow-runtime}/world/streams.mdx +8 -8
- package/docs/api-reference/workflow-serde/index.mdx +1 -2
- package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +3 -4
- package/docs/api-reference/workflow-serde/workflow-serialize.mdx +8 -8
- 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 +53 -41
- package/docs/changelog/batched-event-writes.mdx +79 -0
- package/docs/changelog/eager-processing.mdx +110 -436
- package/docs/changelog/index.mdx +4 -2
- package/docs/changelog/lazy-event-creation.md +127 -0
- package/docs/changelog/lazy-hook-resume.mdx +78 -0
- package/docs/changelog/meta.json +11 -1
- package/docs/changelog/resilient-resume.mdx +32 -0
- package/docs/changelog/resilient-start.mdx +33 -285
- package/docs/changelog/step-message-ownership.mdx +360 -0
- package/docs/changelog/turbo-mode.md +87 -0
- package/docs/comparisons/index.mdx +66 -0
- package/docs/comparisons/meta.json +11 -0
- package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +55 -0
- package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +111 -0
- package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +71 -0
- package/docs/comparisons/workflow-sdk-vs-inngest.mdx +102 -0
- package/docs/comparisons/workflow-sdk-vs-temporal.mdx +123 -0
- package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +104 -0
- package/docs/configuration/build-and-diagnostics.mdx +79 -0
- package/docs/configuration/cli-and-web-ui.mdx +241 -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 +399 -0
- package/docs/configuration/worlds.mdx +315 -0
- package/docs/cookbook/advanced/child-workflows.mdx +33 -25
- package/docs/cookbook/advanced/publishing-libraries.mdx +65 -56
- package/docs/cookbook/advanced/serializable-steps.mdx +48 -68
- package/docs/cookbook/advanced/upgrading-workflows.mdx +35 -31
- package/docs/cookbook/agent-patterns/agent-cancellation.mdx +78 -60
- package/docs/cookbook/agent-patterns/durable-agent.mdx +23 -135
- package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +180 -195
- package/docs/cookbook/common-patterns/batching.mdx +20 -14
- package/docs/cookbook/common-patterns/idempotency.mdx +41 -53
- package/docs/cookbook/common-patterns/rate-limiting.mdx +8 -4
- package/docs/cookbook/common-patterns/saga.mdx +23 -19
- package/docs/cookbook/common-patterns/scheduling.mdx +30 -22
- package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +29 -25
- package/docs/cookbook/common-patterns/timeouts.mdx +26 -21
- package/docs/cookbook/common-patterns/webhooks.mdx +10 -6
- package/docs/cookbook/common-patterns/workflow-composition.mdx +27 -17
- package/docs/cookbook/index.mdx +22 -22
- package/docs/cookbook/integrations/ai-sdk.mdx +63 -48
- package/docs/cookbook/integrations/chat-sdk.mdx +46 -33
- package/docs/cookbook/integrations/sandbox.mdx +58 -45
- package/docs/deploying.mdx +106 -0
- package/docs/errors/abort-signal-timeout-in-workflow.mdx +16 -12
- package/docs/errors/corrupted-event-log.mdx +39 -18
- package/docs/errors/deployment-mismatch.mdx +71 -0
- package/docs/errors/fetch-in-workflow.mdx +15 -14
- package/docs/errors/hook-conflict.mdx +38 -11
- package/docs/errors/hook-force-claimed.mdx +96 -0
- package/docs/errors/index.mdx +24 -37
- package/docs/errors/node-js-module-in-workflow.mdx +9 -5
- package/docs/errors/replay-divergence.mdx +27 -0
- package/docs/errors/run-expired.mdx +85 -0
- package/docs/errors/runtime-decryption-failed.mdx +77 -0
- package/docs/errors/serialization-failed.mdx +44 -12
- package/docs/errors/start-invalid-workflow-function.mdx +9 -5
- package/docs/errors/step-executed-multiple-times.mdx +23 -0
- package/docs/errors/step-not-registered.mdx +6 -6
- package/docs/errors/timeout-in-workflow.mdx +12 -8
- package/docs/errors/webhook-invalid-respond-with-value.mdx +18 -18
- package/docs/errors/webhook-response-not-sent.mdx +20 -16
- package/docs/errors/workflow-not-registered.mdx +5 -5
- package/docs/foundations/cancellation.mdx +31 -32
- package/docs/foundations/errors-and-retries.mdx +54 -11
- package/docs/foundations/hooks.mdx +98 -35
- package/docs/foundations/idempotency.mdx +267 -12
- package/docs/foundations/index.mdx +1 -26
- package/docs/foundations/serialization.mdx +22 -22
- package/docs/foundations/starting-workflows.mdx +104 -30
- package/docs/foundations/streaming.mdx +108 -60
- package/docs/foundations/versioning.mdx +4 -4
- package/docs/foundations/workflows-and-steps.mdx +9 -9
- package/docs/getting-started/astro.mdx +22 -18
- package/docs/getting-started/express.mdx +15 -11
- package/docs/getting-started/fastify.mdx +15 -11
- package/docs/getting-started/hono.mdx +15 -11
- package/docs/getting-started/index.mdx +10 -3
- package/docs/getting-started/meta.json +3 -1
- package/docs/getting-started/nestjs.mdx +264 -21
- package/docs/getting-started/next.mdx +18 -14
- package/docs/getting-started/nitro.mdx +22 -18
- package/docs/getting-started/nuxt.mdx +15 -11
- package/docs/getting-started/python.mdx +190 -41
- package/docs/getting-started/react-router/index.mdx +33 -0
- package/docs/getting-started/react-router/meta.json +5 -0
- package/docs/getting-started/react-router/v7.mdx +237 -0
- package/docs/getting-started/react-router/v8.mdx +232 -0
- package/docs/getting-started/sveltekit.mdx +20 -16
- package/docs/getting-started/tanstack-start.mdx +17 -13
- package/docs/getting-started/vite.mdx +15 -11
- package/docs/how-it-works/cancellation.mdx +63 -63
- package/docs/how-it-works/code-transform.mdx +82 -66
- package/docs/how-it-works/encryption.mdx +30 -26
- package/docs/how-it-works/event-sourcing.mdx +132 -35
- package/docs/how-it-works/framework-integrations.mdx +96 -337
- package/docs/how-it-works/understanding-directives.mdx +22 -22
- package/docs/internal/index.mdx +6 -4
- package/docs/internal/meta.json +6 -1
- 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 +7 -7
- package/docs/meta.json +4 -2
- package/docs/observability/attributes.mdx +91 -21
- package/docs/observability/index.mdx +29 -15
- package/docs/observability/lifecycle-hooks.mdx +95 -0
- package/docs/observability/meta.json +1 -1
- package/docs/observability/retention.mdx +95 -0
- package/docs/observability/tracing.mdx +124 -0
- package/docs/testing/index.mdx +120 -38
- package/docs/testing/server-based.mdx +10 -10
- package/docs/whats-new.mdx +190 -0
- package/docs/worlds/building-a-world.mdx +538 -0
- package/docs/worlds/local.mdx +129 -0
- package/docs/worlds/meta.json +10 -0
- package/docs/worlds/postgres.mdx +424 -0
- package/docs/worlds/upgrading-to-v5.mdx +162 -0
- package/docs/worlds/vercel.mdx +345 -0
- package/package.json +17 -14
- package/docs/api-reference/workflow/experimental-set-attributes.mdx +0 -63
- package/docs/api-reference/workflow-api/world/index.mdx +0 -58
- package/docs/api-reference/workflow-api/world/meta.json +0 -4
- package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
- package/docs/api-reference/workflow-api/world/queue.mdx +0 -86
- package/docs/deploying/building-a-world.mdx +0 -251
- package/docs/deploying/index.mdx +0 -95
- package/docs/deploying/meta.json +0 -4
- package/docs/deploying/world/local-world.mdx +0 -84
- package/docs/deploying/world/meta.json +0 -4
- package/docs/deploying/world/postgres-world.mdx +0 -224
- package/docs/deploying/world/vercel-world.mdx +0 -181
- package/docs/migration-guides/index.mdx +0 -34
- package/docs/migration-guides/meta.json +0 -9
- package/docs/migration-guides/migrating-from-aws-step-functions.mdx +0 -358
- package/docs/migration-guides/migrating-from-inngest.mdx +0 -304
- package/docs/migration-guides/migrating-from-temporal.mdx +0 -313
- package/docs/migration-guides/migrating-from-trigger-dev.mdx +0 -328
|
@@ -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,37 @@ export async function POST(request: Request) {
|
|
|
289
314
|
}
|
|
290
315
|
```
|
|
291
316
|
|
|
292
|
-
##
|
|
317
|
+
## Writing to another run's stream
|
|
318
|
+
|
|
319
|
+
`getRun(runId).getWritable()` appends to a stream owned by another run. This lets short-lived runs contribute to a long-lived holder run's stream using only its ID.
|
|
293
320
|
|
|
294
|
-
|
|
321
|
+
```typescript title="workflows/turn.ts" lineNumbers
|
|
322
|
+
import { getRun } from "workflow/api";
|
|
323
|
+
|
|
324
|
+
type SessionEvent = { turn: number; text: string };
|
|
325
|
+
|
|
326
|
+
async function runTurn(holderRunId: string, turn: number) {
|
|
327
|
+
"use step";
|
|
328
|
+
|
|
329
|
+
const writable = getRun(holderRunId).getWritable<SessionEvent>(); // [!code highlight]
|
|
330
|
+
const writer = writable.getWriter();
|
|
331
|
+
|
|
332
|
+
await writer.write({ turn, text: "done" });
|
|
333
|
+
writer.releaseLock(); // [!code highlight]
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Pass `{ namespace: "name" }` to target a [namespaced stream](#namespaced-streams). The writable can also be forwarded through `start()` and into steps.
|
|
338
|
+
|
|
339
|
+
<Callout type="warn">
|
|
340
|
+
Contributors should call `releaseLock()`, which flushes pending writes. Calling `close()` closes the shared stream for every writer.
|
|
341
|
+
</Callout>
|
|
342
|
+
|
|
343
|
+
The API grants append access, not read access or additional authorization. The owning run controls the stream's lifecycle, and writes to an unknown run fail.
|
|
344
|
+
|
|
345
|
+
## Common patterns
|
|
346
|
+
|
|
347
|
+
### Progress updates for long-running tasks
|
|
295
348
|
|
|
296
349
|
Send incremental progress updates to keep users informed during lengthy workflows:
|
|
297
350
|
|
|
@@ -345,29 +398,19 @@ export async function batchProcessingWorkflow(items: string[]) {
|
|
|
345
398
|
}
|
|
346
399
|
```
|
|
347
400
|
|
|
348
|
-
### Streaming AI
|
|
401
|
+
### Streaming AI responses with `WorkflowAgent`
|
|
349
402
|
|
|
350
|
-
Stream AI-generated content using [`
|
|
403
|
+
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
404
|
|
|
352
405
|
```typescript title="workflows/ai-assistant.ts" lineNumbers
|
|
353
|
-
import {
|
|
406
|
+
import { WorkflowAgent, type ModelCallStreamPart } from "@ai-sdk/workflow";
|
|
407
|
+
import { tool } from "ai";
|
|
354
408
|
import { getWritable } from "workflow";
|
|
355
409
|
import { z } from "zod";
|
|
356
|
-
import type { UIMessageChunk } from "ai";
|
|
357
410
|
|
|
358
411
|
async function searchFlights({ query }: { query: string }) {
|
|
359
412
|
"use step";
|
|
360
413
|
|
|
361
|
-
// Tools can emit progress updates to the stream
|
|
362
|
-
const writable = getWritable<UIMessageChunk>(); // [!code highlight]
|
|
363
|
-
const writer = writable.getWriter(); // [!code highlight]
|
|
364
|
-
await writer.write({ // [!code highlight]
|
|
365
|
-
type: "data-progress", // [!code highlight]
|
|
366
|
-
data: { message: `Searching flights for ${query}...` }, // [!code highlight]
|
|
367
|
-
transient: true, // [!code highlight]
|
|
368
|
-
}); // [!code highlight]
|
|
369
|
-
writer.releaseLock(); // [!code highlight]
|
|
370
|
-
|
|
371
414
|
// ... search logic ...
|
|
372
415
|
return { flights: [/* results */] };
|
|
373
416
|
}
|
|
@@ -375,27 +418,28 @@ async function searchFlights({ query }: { query: string }) {
|
|
|
375
418
|
export async function aiAssistantWorkflow(userMessage: string) {
|
|
376
419
|
"use workflow";
|
|
377
420
|
|
|
378
|
-
const agent = new
|
|
379
|
-
model: "
|
|
380
|
-
|
|
421
|
+
const agent = new WorkflowAgent({
|
|
422
|
+
model: "spacexai/grok-4.6",
|
|
423
|
+
instructions: "You are a helpful flight assistant.",
|
|
381
424
|
tools: {
|
|
382
|
-
searchFlights: {
|
|
425
|
+
searchFlights: tool({
|
|
383
426
|
description: "Search for flights",
|
|
384
427
|
inputSchema: z.object({ query: z.string() }),
|
|
385
428
|
execute: searchFlights,
|
|
386
|
-
},
|
|
429
|
+
}),
|
|
387
430
|
},
|
|
388
431
|
});
|
|
389
432
|
|
|
390
433
|
// LLM response will be streamed to the run's writable
|
|
391
434
|
await agent.stream({
|
|
392
435
|
messages: [{ role: "user", content: userMessage }],
|
|
393
|
-
writable: getWritable<
|
|
436
|
+
writable: getWritable<ModelCallStreamPart>(), // [!code highlight]
|
|
394
437
|
});
|
|
395
438
|
}
|
|
396
439
|
```
|
|
397
440
|
|
|
398
441
|
```typescript title="app/api/ai-assistant/route.ts" lineNumbers
|
|
442
|
+
import { createModelCallToUIChunkTransform } from "@ai-sdk/workflow";
|
|
399
443
|
import { createUIMessageStreamResponse } from "ai";
|
|
400
444
|
import { start } from "workflow/api";
|
|
401
445
|
import { aiAssistantWorkflow } from "./workflows/ai";
|
|
@@ -406,16 +450,16 @@ export async function POST(request: Request) {
|
|
|
406
450
|
const run = await start(aiAssistantWorkflow, [message]);
|
|
407
451
|
|
|
408
452
|
return createUIMessageStreamResponse({
|
|
409
|
-
stream: run.readable,
|
|
453
|
+
stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()), // [!code highlight]
|
|
410
454
|
});
|
|
411
455
|
}
|
|
412
456
|
```
|
|
413
457
|
|
|
414
458
|
<Callout type="info">
|
|
415
|
-
For
|
|
459
|
+
For the full agent API and migration notes, see the [`WorkflowAgent` documentation](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent).
|
|
416
460
|
</Callout>
|
|
417
461
|
|
|
418
|
-
### Streaming
|
|
462
|
+
### Streaming between steps
|
|
419
463
|
|
|
420
464
|
One step produces a stream and another step consumes it:
|
|
421
465
|
|
|
@@ -456,7 +500,7 @@ async function consumeData(readable: ReadableStream<number>) {
|
|
|
456
500
|
}
|
|
457
501
|
```
|
|
458
502
|
|
|
459
|
-
### Processing
|
|
503
|
+
### Processing large files without memory overhead
|
|
460
504
|
|
|
461
505
|
Process large files by streaming chunks through transformation steps:
|
|
462
506
|
|
|
@@ -497,7 +541,11 @@ async function uploadResult(stream: ReadableStream<Uint8Array>) {
|
|
|
497
541
|
}
|
|
498
542
|
```
|
|
499
543
|
|
|
500
|
-
## Best
|
|
544
|
+
## Best practices
|
|
545
|
+
|
|
546
|
+
**Batching and first-chunk latency:**
|
|
547
|
+
|
|
548
|
+
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).
|
|
501
549
|
|
|
502
550
|
**Release locks properly:**
|
|
503
551
|
|
|
@@ -515,7 +563,7 @@ Stream locks acquired in a step only apply within that step, not across other st
|
|
|
515
563
|
</Callout>
|
|
516
564
|
|
|
517
565
|
<Callout type="warn">
|
|
518
|
-
If a lock is not released, the
|
|
566
|
+
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.
|
|
519
567
|
</Callout>
|
|
520
568
|
|
|
521
569
|
**Close streams when done:**
|
|
@@ -541,7 +589,7 @@ const writer = writable.getWriter();
|
|
|
541
589
|
await writer.write({ /* typed data */ });
|
|
542
590
|
```
|
|
543
591
|
|
|
544
|
-
## Stream
|
|
592
|
+
## Stream failures
|
|
545
593
|
|
|
546
594
|
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).
|
|
547
595
|
|
|
@@ -584,17 +632,17 @@ export async function streamErrorWorkflow() {
|
|
|
584
632
|
```
|
|
585
633
|
|
|
586
634
|
<Callout type="info">
|
|
587
|
-
Stream errors don't trigger automatic retries for the producer step. Design your stream consumers to handle errors
|
|
635
|
+
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.
|
|
588
636
|
</Callout>
|
|
589
637
|
|
|
590
|
-
## Related
|
|
591
|
-
|
|
592
|
-
- [`getWritable()` API
|
|
593
|
-
- [`sleep()` API
|
|
594
|
-
- [`start()` API
|
|
595
|
-
- [`getRun()` API
|
|
596
|
-
- [world.streams](/docs/api-reference/workflow-
|
|
597
|
-
- [
|
|
598
|
-
- [Errors and
|
|
599
|
-
- [Serialization](/docs/foundations/serialization)
|
|
600
|
-
- [Workflows and
|
|
638
|
+
## Related documentation
|
|
639
|
+
|
|
640
|
+
- [`getWritable()` API reference](/docs/api-reference/workflow/get-writable): Get the workflow's writable stream
|
|
641
|
+
- [`sleep()` API reference](/docs/api-reference/workflow/sleep): Pause workflow execution for a duration
|
|
642
|
+
- [`start()` API reference](/docs/api-reference/workflow-api/start): Start workflows and access the `Run` object
|
|
643
|
+
- [`getRun()` API reference](/docs/api-reference/workflow-api/get-run): Retrieve runs and their streams later
|
|
644
|
+
- [`world.streams`](/docs/api-reference/workflow-runtime/world/streams): Use low-level stream read, write, and close operations through the World SDK
|
|
645
|
+
- [`WorkflowAgent`](https://ai-sdk.dev/v7/docs/agents/workflow-agent#workflowagent): Build AI agents with durable, resumable streaming support
|
|
646
|
+
- [Errors and retries](/docs/foundations/errors-and-retries): Understand error handling and retry behavior
|
|
647
|
+
- [Serialization](/docs/foundations/serialization): Understand which data types you can pass in workflows
|
|
648
|
+
- [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.
|
|
@@ -94,7 +94,7 @@ npx workflow cancel \
|
|
|
94
94
|
--backend vercel
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
The `--workflowName` filter expects the generated workflow ID, not only the exported function's short name. Use the `workflowName` value from `workflow inspect runs`, and use [`parseWorkflowName()`](/docs/api-reference/workflow-
|
|
97
|
+
The `--workflowName` filter expects the generated workflow ID, not only the exported function's short name. Use the `workflowName` value from `workflow inspect runs`, and use [`parseWorkflowName()`](/docs/api-reference/workflow-observability/parse-workflow-name) when you need display-friendly names.
|
|
98
98
|
|
|
99
99
|
In the [observability UI](/docs/observability), use **Rerun on latest** to enqueue the workflow again with the same inputs against the latest deployment.
|
|
100
100
|
|
|
@@ -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";
|
|
@@ -14,18 +14,18 @@ import { File, Folder, Files } from "fumadocs-ui/components/files";
|
|
|
14
14
|
|
|
15
15
|
Workflows (a.k.a. *durable functions*) are a programming model for building long-running, stateful application logic that can maintain its execution state across restarts, failures, or user events. Unlike traditional serverless functions that lose all state when they terminate, workflows persist their progress and can resume exactly where they left off.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Workflows let you model complex multi-step processes in code. To do this, we introduce two fundamental entities:
|
|
18
18
|
|
|
19
19
|
1. **Workflow Functions**: Functions that orchestrate/organize steps
|
|
20
20
|
2. **Step Functions**: Functions that carry out the actual work
|
|
21
21
|
|
|
22
|
-
## Workflow
|
|
22
|
+
## Workflow functions
|
|
23
23
|
|
|
24
24
|
*Directive: `"use workflow"`*
|
|
25
25
|
|
|
26
26
|
Workflow functions define the entrypoint of a workflow and organize how step functions are called. This type of function does not have access to the Node.js runtime, and usable `npm` packages are limited.
|
|
27
27
|
|
|
28
|
-
Although this may seem limiting initially, this feature is
|
|
28
|
+
Although this may seem limiting initially, this feature is required to suspend and accurately resume workflow execution.
|
|
29
29
|
|
|
30
30
|
It helps to think of the workflow function less like a full JavaScript runtime and more like "stitching together" various steps using conditionals, loops, try/catch handlers, `Promise.all`, and other language primitives.
|
|
31
31
|
|
|
@@ -51,7 +51,7 @@ Determinism in the workflow is required to resume the workflow from a suspension
|
|
|
51
51
|
|
|
52
52
|
The sandboxed environment that workflows run in already ensures determinism. For instance, `Math.random` and `Date` constructors are fixed in workflow runs, so you are safe to use them, and the framework ensures that the values don't change across replays.
|
|
53
53
|
|
|
54
|
-
## Step
|
|
54
|
+
## Step functions
|
|
55
55
|
|
|
56
56
|
*Directive: `"use step"`*
|
|
57
57
|
|
|
@@ -115,10 +115,10 @@ export async function POST() {
|
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
<Callout type="info">
|
|
118
|
-
|
|
118
|
+
Calling a step function outside a workflow function provides neither retry semantics nor observability. Additionally, certain workflow-specific functions like [`getStepMetadata()`](/docs/api-reference/workflow/get-step-metadata) will throw an error when used inside a step that's called outside a workflow.
|
|
119
119
|
</Callout>
|
|
120
120
|
|
|
121
|
-
### Suspension and
|
|
121
|
+
### Suspension and resumption
|
|
122
122
|
|
|
123
123
|
Workflow functions have the ability to automatically suspend while they wait on asynchronous work. While suspended, the workflow's state is stored via the [event log](/docs/how-it-works/event-sourcing) and no compute resources are used until the workflow resumes execution.
|
|
124
124
|
|
|
@@ -126,7 +126,7 @@ Workflow functions have the ability to automatically suspend while they wait on
|
|
|
126
126
|
|
|
127
127
|
There are multiple ways a workflow can suspend:
|
|
128
128
|
|
|
129
|
-
- Waiting on a step function: the workflow yields while the step runs in the step
|
|
129
|
+
- Waiting on a step function: the workflow yields while the step body runs. The step usually executes inline in the same invocation; when the invocation's inline budget is exhausted or its timeout approaches, the step is handed to the queue and the workflow resumes in a later invocation.
|
|
130
130
|
- Using `sleep()` to pause for some fixed duration.
|
|
131
131
|
- Awaiting on a promise returned by [`createWebhook()`](/docs/api-reference/workflow/create-webhook), which resumes the workflow when an external system passes data into the workflow.
|
|
132
132
|
|
|
@@ -150,9 +150,9 @@ export async function documentReviewProcess(userId: string) {
|
|
|
150
150
|
}
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
## Writing
|
|
153
|
+
## Writing workflows
|
|
154
154
|
|
|
155
|
-
### Basic
|
|
155
|
+
### Basic structure
|
|
156
156
|
|
|
157
157
|
The simplest workflow consists of a workflow function and one or more step functions.
|
|
158
158
|
|
|
@@ -9,16 +9,20 @@ related:
|
|
|
9
9
|
- /docs/foundations/workflows-and-steps
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
<CopyPrompt
|
|
13
|
+
text="In this Astro app, run `npm i workflow`. In `astro.config.mjs`, import `workflow` from `workflow/astro` and add `integrations: [workflow()]`. Add the TypeScript plugin `{ "name": "workflow" }` to `tsconfig.json` if TypeScript is used. Create `src/workflows/user-signup.ts` exporting `handleUserSignup(email)` with `"use workflow"`, `sleep` from `workflow`, and `"use step"` helpers. Add `src/pages/api/signup.ts` exporting `POST: APIRoute` that reads `{ email }`, calls `start(handleUserSignup, [email])` from `workflow/api`, returns `Response.json`, and sets `prerender = false`. Run `npm run dev`, call `curl -X POST --json '{"email":"hello@example.com"}' http://localhost:4321/api/signup`, and inspect with `npx workflow inspect runs`."
|
|
14
|
+
/>
|
|
15
|
+
|
|
16
|
+
Set up your first durable workflow in an Astro app and learn the core Workflow SDK concepts.
|
|
13
17
|
|
|
14
18
|
---
|
|
15
19
|
|
|
16
20
|
<Steps>
|
|
17
21
|
|
|
18
22
|
<Step>
|
|
19
|
-
## Create
|
|
23
|
+
## Create your Astro project
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
Create an Astro project in a new directory named `my-workflow-app`:
|
|
22
26
|
|
|
23
27
|
```bash
|
|
24
28
|
npm create astro@latest my-workflow-app -- --template minimal --install --yes
|
|
@@ -55,16 +59,16 @@ export default defineConfig({
|
|
|
55
59
|
|
|
56
60
|
| Option | Type | Default | Description |
|
|
57
61
|
| --- | --- | --- | --- |
|
|
58
|
-
| `sourcemap` | `boolean \| 'inline' \| 'linked' \| 'external' \| 'both'` | `'inline'` | Controls source maps on generated workflow bundles. Accepts the same values as esbuild's `sourcemap` option.
|
|
62
|
+
| `sourcemap` | `boolean \| 'inline' \| 'linked' \| 'external' \| 'both'` | `'inline'` (dev) / `false` (prod) | Controls source maps on generated workflow bundles. Accepts the same values as esbuild's `sourcemap` option. Defaults to `'inline'` in development and `false` in production (smaller function bundles, which helps stay under the Vercel 250 MB function size limit). Set it explicitly, or use the `WORKFLOW_SOURCEMAP` environment variable, to override in either environment. |
|
|
59
63
|
|
|
60
64
|
<Accordion type="single" collapsible>
|
|
61
65
|
<AccordionItem value="typescript-intellisense" className="[&_h3]:my-0">
|
|
62
66
|
<AccordionTrigger className="text-sm">
|
|
63
|
-
###
|
|
67
|
+
### Set up IntelliSense for TypeScript (optional)
|
|
64
68
|
</AccordionTrigger>
|
|
65
69
|
<AccordionContent className="[&_p]:my-2">
|
|
66
70
|
|
|
67
|
-
To enable helpful hints in your IDE,
|
|
71
|
+
To enable helpful hints in your IDE, set up the workflow plugin in `tsconfig.json`:
|
|
68
72
|
|
|
69
73
|
```json title="tsconfig.json" lineNumbers
|
|
70
74
|
{
|
|
@@ -87,7 +91,7 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json
|
|
|
87
91
|
|
|
88
92
|
<Step>
|
|
89
93
|
|
|
90
|
-
## Create
|
|
94
|
+
## Create your first workflow
|
|
91
95
|
|
|
92
96
|
Create a new file for our first workflow:
|
|
93
97
|
|
|
@@ -108,14 +112,14 @@ export async function handleUserSignup(email: string) {
|
|
|
108
112
|
|
|
109
113
|
```
|
|
110
114
|
|
|
111
|
-
We'll fill in those functions next, but
|
|
115
|
+
We'll fill in those functions next, but first review this code:
|
|
112
116
|
|
|
113
117
|
* We define a **workflow** function with the directive `"use workflow"`. Think of the workflow function as the _orchestrator_ of individual **steps**.
|
|
114
118
|
* The Workflow SDK's `sleep` function allows us to suspend execution of the workflow without using up any resources. A sleep can be a few seconds, hours, days, or even months long.
|
|
115
119
|
|
|
116
|
-
## Create
|
|
120
|
+
## Create your workflow steps
|
|
117
121
|
|
|
118
|
-
|
|
122
|
+
Define the missing functions.
|
|
119
123
|
|
|
120
124
|
```typescript title="src/workflows/user-signup.ts" lineNumbers
|
|
121
125
|
import { FatalError } from "workflow"
|
|
@@ -156,7 +160,7 @@ async function sendOnboardingEmail(user: { id: string; email: string}) {
|
|
|
156
160
|
|
|
157
161
|
Taking a look at this code:
|
|
158
162
|
|
|
159
|
-
* Business logic lives inside **steps**. When a
|
|
163
|
+
* Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
|
|
160
164
|
* If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
|
|
161
165
|
* Steps can throw a `FatalError` if an error is intentional and should not be retried.
|
|
162
166
|
|
|
@@ -168,7 +172,7 @@ We'll dive deeper into workflows, steps, and other ways to suspend or handle eve
|
|
|
168
172
|
|
|
169
173
|
<Step>
|
|
170
174
|
|
|
171
|
-
## Create
|
|
175
|
+
## Create your route handler
|
|
172
176
|
|
|
173
177
|
To invoke your new workflow, we'll have to add your workflow to a `POST` API route handler, `src/pages/api/signup.ts` with the following code:
|
|
174
178
|
|
|
@@ -200,7 +204,7 @@ Workflows can be triggered from API routes or any server-side code.
|
|
|
200
204
|
|
|
201
205
|
</Steps>
|
|
202
206
|
|
|
203
|
-
## Run in
|
|
207
|
+
## Run in development
|
|
204
208
|
|
|
205
209
|
To start your development server, run the following command in your terminal in the Vite root directory:
|
|
206
210
|
|
|
@@ -227,9 +231,9 @@ npx workflow inspect runs
|
|
|
227
231
|
|
|
228
232
|
---
|
|
229
233
|
|
|
230
|
-
## Deploying to
|
|
234
|
+
## Deploying to production
|
|
231
235
|
|
|
232
|
-
Workflow SDK apps currently work best when deployed to [Vercel](https://vercel.com/home) and
|
|
236
|
+
Workflow SDK apps currently work best when deployed to [Vercel](https://vercel.com/home) and need no special configuration.
|
|
233
237
|
|
|
234
238
|
<FluidComputeCallout />
|
|
235
239
|
|
|
@@ -247,8 +251,8 @@ Additionally, check the [Deploying](/docs/deploying) section to learn how your w
|
|
|
247
251
|
|
|
248
252
|
If you see this error:
|
|
249
253
|
|
|
250
|
-
```
|
|
251
|
-
'start' received an invalid workflow function. Ensure the Workflow
|
|
254
|
+
```text
|
|
255
|
+
'start' received an invalid workflow function. Ensure the Workflow SDK is configured correctly and the function includes a 'use workflow' directive.
|
|
252
256
|
```
|
|
253
257
|
|
|
254
258
|
Check both of these first:
|
|
@@ -258,7 +262,7 @@ Check both of these first:
|
|
|
258
262
|
|
|
259
263
|
See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function) for full examples and fixes.
|
|
260
264
|
|
|
261
|
-
## Next
|
|
265
|
+
## Next steps
|
|
262
266
|
|
|
263
267
|
* Learn more about the [Foundations](/docs/foundations).
|
|
264
268
|
* Check [Errors](/docs/errors) if you encounter issues.
|