Skip to content

Commit cc2f3c2

Browse files
committed
Merge branch 'silverlock/workflows/new' of github.com:cloudflare/cloudflare-docs into silverlock/workflows/new
2 parents dcdf9ee + 86ba2a8 commit cc2f3c2

File tree

20 files changed

+180
-153
lines changed

20 files changed

+180
-153
lines changed

src/content/changelogs/workflows.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ entries:
88
- publish_date: "2038-01-19"
99
title: Workflows is now in public beta.
1010
description: |-
11-
Workflows, a new product for building reliable, multi-step workflows using Cloudflare Workers, is now in public beta. The public beta is avaiable to any user with a [free or paid Workers plan](/workers/platform/pricing/).
11+
Workflows, a new product for building reliable, multi-step workflows using Cloudflare Workers, is now in public beta. The public beta is available to any user with a [free or paid Workers plan](/workers/platform/pricing/).
1212
1313
A Workflow allows you to define multiple, independent steps that encapsulate errors, automatically retry, persist state, and can run for seconds, minutes, hours or even days. A Workflow can be useful for post-processing data from R2 buckets before querying it, automating a [Workers AI RAG pipeline](/workers-ai/tutorials/build-a-retrieval-augmented-generation-ai/), or managing user signup flows and lifecycle emails.
1414

src/content/docs/workers/runtime-apis/bindings/workflows.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
pcx_content_type: navigation
3-
title: Vectorize
3+
title: Workflows
44
external_link: /workflows/
55
head: []
66
description: APIs available in Cloudflare Workers to interact with

src/content/docs/workers/wrangler/commands.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,9 +1258,9 @@ wrangler workflows list
12581258
```
12591259

12601260
- `--page` <Type text="number" /> <MetaInfo text="optional" />
1261-
- Show a sepecific page from the listing, can configure page size using "per-page"
1261+
- Show a specific page from the listing. You can configure page size using "per-page".
12621262
- `--per-page` <Type text="number" /> <MetaInfo text="optional" />
1263-
- Configure the maximum number of workflows to show per page.
1263+
- Configure the maximum number of Workflows to show per page.
12641264

12651265
### `instances`
12661266

src/content/docs/workflows/build/dynamic-steps.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ sidebar:
88

99
A Workflow does not have to define all of its steps statically: steps can be created programmatically and/or conditionally.
1010

11-
This allows you to not only trigger steps based on specific input parameters, but to also name steps dynamically, set the retry configuration for a step
11+
This allows you to not only trigger steps based on specific input parameters, but to also name steps dynamically and set the retry configuration for a single step.
1212

1313

1414
## Example
1515

16-
Steps can be created on-the-fly, allowing you create a step for each parameter passed to your Workflow, for each file you want to read from storage, or for calls to third-party APIs.
16+
You can create steps on-the-fly. You can create a step for each parameter passed to your Workflow, for each file you want to read from storage, or for calls to third-party APIs.
1717

1818
For example, you can loop over each event, label the step dynamically, and have the step operate only over that `event`:
1919

src/content/docs/workflows/build/events-and-parameters.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ When a Workflow is triggered, it can receive an optional event. This event can i
1010

1111
Events are a powerful part of a Workflow, as you often want a Workflow to act on data. Because a given Workflow instance executes durably, events are a useful way to provide a Workflow with data that should be immutable (not changing) and/or represents data the Workflow needs to operate on at that point in time.
1212

13-
## Passing parameters to a Workflow
13+
## Pass parameters to a Workflow
1414

1515
You can pass parameters to a Workflow in two ways:
1616

17-
* As an optional argument to the `create` method on a [Workflow binding] when triggering a Workflow from a Worker.
17+
* As an optional argument to the `create` method on a [Workflow binding](/workers/wrangler/commands/#trigger) when triggering a Workflow from a Worker.
1818
* Via the `--params` flag when using the `wrangler` CLI to trigger a Workflow.
1919

2020
You can pass any JSON-serializable object as a parameter.
@@ -80,7 +80,7 @@ interface YourEventType {
8080
}
8181
```
8282

83-
When we pass our `YourEventType` to `WorkflowEvent` as a type parameter, the `event.payload` property now has the type `YourEventType` throughout our workflow definition:
83+
When you pass your `YourEventType` to `WorkflowEvent` as a type parameter, the `event.payload` property now has the type `YourEventType` throughout your workflow definition:
8484

8585
```ts title="src/index.ts"
8686
// Import the Workflow definition

src/content/docs/workflows/build/index.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ title: Build with Workflows
33
pcx_content_type: navigation
44
sidebar:
55
order: 2
6+
group:
7+
hideIndex: true
68

79
---
810

src/content/docs/workflows/build/rules-of-workflows.mdx

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ sidebar:
55
order: 10
66
---
77

8-
A Workflow contains one or more steps. Each step is a self-contained, individually retriable component of a Workflow. Steps may emit (optional) state that allows a Workflow to persist and continue from that step, even if a Workflow fails due to a network or infrastructure issue. A Workflow is comprised of one or more steps.
8+
A Workflow contains one or more steps. Each step is a self-contained, individually retriable component of a Workflow. Steps may emit (optional) state that allows a Workflow to persist and continue from that step, even if a Workflow fails due to a network or infrastructure issue.
99

1010
This is a small guidebook on how to build more resilient and correct Workflows.
1111

1212
### Ensure API/Binding calls are idempotent
1313

1414
Because a step might be retried multiple times, your steps should (ideally) be idempotent. For context, idempotency is a logical property where the operation (in this case a step),
15-
can be applied multiple times without changing the result beyond the intial application.
15+
can be applied multiple times without changing the result beyond the initial application.
1616

17-
As an example, let's assume you have a Workflow that charges your customers and you really don't want to charge them twice by accident, before charging them, you should
17+
As an example, let us assume you have a Workflow that charges your customers, and you really do not want to charge them twice by accident. Before charging them, you should
1818
check if they were already charged:
1919

2020
```ts
@@ -55,13 +55,13 @@ export class MyWorkflow extends WorkflowEntrypoint {
5555

5656
:::note
5757

58-
Guaranteeing idempotency might be optional in your specific use-case and implementation, although we recommend it to always try to guarantee it.
58+
Guaranteeing idempotency might be optional in your specific use-case and implementation, but we recommend that you always try to guarantee it.
5959

6060
:::
6161

6262
### Make your steps granular
6363

64-
Steps should be as self-contained as possible, this allows your own logic to be more durable in case of failures in third-party APIs, network errors, and so on.
64+
Steps should be as self-contained as possible. This allows your own logic to be more durable in case of failures in third-party APIs, network errors, and so on.
6565

6666
You can also think of it as a transaction, or a unit of work.
6767

@@ -85,12 +85,12 @@ export class MyWorkflow extends WorkflowEntrypoint {
8585
}
8686
```
8787

88-
Otherwise your entire workflow might not be as durable as you might think, and encounter into some undefined behaviour and you can avoid them by:
88+
Otherwise, your entire Workflow might not be as durable as you might think, and you may encounter some undefined behaviour. You can avoid them by following the rules below:
8989

9090
- 🔴 Do not encapsulate your entire logic in one single step.
91-
- 🔴 Do not call seperate services in the same step (unless you need it to prove idempotency)
92-
- 🔴 Do not make too many service calls in the same step (unless you need it to prove idempotency)
93-
- 🔴 Do not do too much CPU-intensive work inside of a single step - sometimes engine might have to restart and it will start over from that step.
91+
- 🔴 Do not call separate services in the same step (unless you need it to prove idempotency).
92+
- 🔴 Do not make too many service calls in the same step (unless you need it to prove idempotency).
93+
- 🔴 Do not do too much CPU-intensive work inside a single step - sometimes the engine may have to restart, and it will start over from the beginning of that step.
9494

9595
```ts
9696
export class MyWorkflow extends WorkflowEntrypoint {
@@ -106,9 +106,9 @@ export class MyWorkflow extends WorkflowEntrypoint {
106106
}
107107
```
108108

109-
### Don't rely on state outside of a step
109+
### Do not rely on state outside of a step
110110

111-
Workflows may hibernate and lose all in-memory state. This will happen when engine detects that there's no pending work and can hibernate until it needs to wake-up (because of a sleep, retry or event).
111+
Workflows may hibernate and lose all in-memory state. This will happen when engine detects that there is no pending work and can hibernate until it needs to wake-up (because of a sleep, retry, or event).
112112

113113
This means that you should not store state outside of a step:
114114

@@ -193,14 +193,34 @@ export class MyWorkflow extends WorkflowEntrypoint {
193193
}
194194
```
195195

196-
### Set sensible retry parameters
196+
### Do not mutate your incoming events
197197

198-
TODO
198+
The `event` passed to your Workflow's `run` method is immutable: changes you make to the event are not persisted across steps and/or Workflow restarts.
199199

200-
### Name your steps clearly
201-
202-
TODO
203-
204-
### Don't mutate your incoming events
200+
```ts
201+
interface MyEvent {
202+
user: string;
203+
data: string;
204+
}
205205

206-
TODO
206+
export class MyWorkflow extends WorkflowEntrypoint {
207+
async run(event: WorkflowEvent<MyEvent>, step: WorkflowStep) {
208+
// 🔴 Bad: Mutating the event
209+
// This will not be persisted across steps and `event.data` will
210+
// take on its original value.
211+
await step.do("bad step that mutates the incoming event", async () => {
212+
let userData = await env.KV.get(event.user)
213+
event.data = userData
214+
})
215+
216+
// ✅ Good: persist data by returning it as state from your step
217+
// Use that state in subsequent steps
218+
let userData = await step.do("good step that returns state", async () => {
219+
return await env.KV.get(event.user)
220+
})
221+
222+
let someOtherData await step.do("following step that uses that state", async () => {
223+
// Access to userData here
224+
// Will always be the same if this step is retried
225+
})
226+
```

src/content/docs/workflows/build/sleeping-and-retrying.mdx

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,49 @@ sidebar:
66

77
---
88

9-
TODO
9+
This guide details how to sleep a Workflow and/or configure retries for a Workflow step.
1010

11-
## Sleeping
11+
## Sleep a Workflow
1212

13-
TODO
13+
You can set a Workflow to sleep as an explicit step, which can be useful when you want a Workflow to wait, schedule work ahead, or pause until an input or other external state is ready.
1414

1515
:::note
1616

1717
A Workflow instance that is resuming from sleep will take priority over newly scheduled (queued) instances. This helps ensure that older Workflow instances can run to completion and are not blocked by newer instances.
1818

1919
:::
2020

21+
### Sleep for a relative period
2122

22-
## Retrying steps
23+
Use `step.sleep` to have a Workflow sleep for a relative period of time:
24+
25+
```ts
26+
await step.sleep("sleep for a bit", "1 hour")
27+
```
28+
29+
The second argument to `step.sleep` accepts both `number` (seconds) or a human-readable format, such as "1 minute" or "26 hours". The accepted units for `step.sleep` when used this way are as follows:
30+
31+
```ts
32+
| "second"
33+
| "minute"
34+
| "hour"
35+
| "day"
36+
| "week"
37+
| "month"
38+
| "year"
39+
```
40+
41+
### Sleep until a fixed date
42+
43+
Use `step.sleepUntil` to have a Workflow sleep to a specific `Date`: this can be useful when you have a timestamp from another system or want to "schedule" work to occur at a specific time (e.g. Sunday, 9AM UTC).
44+
45+
```ts
46+
// sleepUntil accepts a Date object as its second argument
47+
const workflowsLaunchDate = Date.parse("24 Oct 2024 13:00:00 UTC");
48+
await step.sleepUntil("sleep until X times out", workflowsLaunchDate)
49+
```
50+
51+
## Retry steps
2352

2453
Each call to `step.do` in a Workflow accepts an optional `StepConfig`, which allows you define the retry behaviour for that step.
2554

@@ -41,7 +70,7 @@ When providing your own `StepConfig`, you can configure:
4170
* The total number of attempts to make for a step
4271
* The delay between attempts
4372
* What backoff algorithm to apply between each attempt: any of `constant`, `linear`, or `exponential`
44-
* When to timeout (in duration) before considering the step as failed (including during a retry attempt).
73+
* When to timeout (in duration) before considering the step as failed (including during a retry attempt)
4574

4675
For example, to limit a step to 10 retries and have it apply an exponential delay (starting at 10 seconds) between each attempt, you would pass the following configuration as an optional object to `step.do`:
4776

@@ -55,3 +84,27 @@ let someState = step.do("call an API", {
5584
timeout: "30 minutes",
5685
}, async () => { /* Step code goes here /* }
5786
```
87+
88+
## Force a Workflow to fail
89+
90+
You can also force a Workflow instance to fail and _not_ retry by throwing a `NonRetryableError` from within the step.
91+
92+
This can be useful when you detect a terminal (permanent) error from an upstream system (such as an authentication failure) or other errors where retrying would not help.
93+
94+
```ts
95+
// Import the NonRetryableError definition
96+
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent, NonRetryableError } from 'cloudflare:workers';
97+
98+
// In your step code:
99+
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
100+
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
101+
await step.do("some step", async () => {
102+
if !(event.data) {
103+
throw NonRetryableError("event.data did not contain the expected payload")
104+
}
105+
})
106+
}
107+
}
108+
```
109+
110+
The Workflow instance itself will fail immediately, no further steps will be invoked, and the Workflow will not be retried.

src/content/docs/workflows/build/trigger-workflows.mdx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ sidebar:
66

77
---
88

9-
TODO - intro
9+
You can trigger Workflows both programmatically and via the Workflows APIs, including:
10+
11+
1. With [Workers](/workers) via HTTP requests in a `fetch` handler, or bindings from a `queue` or `scheduled` handler
12+
2. Using the [Workflows REST API](/api/paths/accounts-account_id--workflows/get)
13+
2. Via the [wrangler CLI](/workers/wrangler/commands/#workflows) in your terminal
1014

1115
## Workers API (Bindings)
1216

@@ -17,7 +21,7 @@ You can interact with a Workflow:
1721
* Directly over HTTP via the [`fetch`](/workers/runtime-apis/handlers/fetch/) handler
1822
* From a [Queue consumer](/queues/configuration/javascript-apis/#consumer) inside a `queue` handler
1923
* From a [Cron Trigger](/workers/configuration/cron-triggers/) inside a `scheduled` handler
20-
* Within a [Durable Object](/durable-objects/).
24+
* Within a [Durable Object](/durable-objects/)
2125

2226
:::note
2327

@@ -52,7 +56,7 @@ The following example shows how you can manage Workflows from within a Worker, i
5256

5357
* Retrieving the status of an existing Workflow instance by its ID
5458
* Creating (triggering) a new Workflow instance
55-
* Returning the status of a given instance ID.
59+
* Returning the status of a given instance ID
5660

5761
```ts title="src/index.ts"
5862
interface Env {
@@ -89,7 +93,7 @@ export default {
8993

9094
### Inspect a Workflow's status
9195

92-
You can inspect the status of any running Workflow instance by calling `status` against a specific instance ID. This allows you to programmatically inspect whether an instance is queued (waiting to be scheduled), actively running, paused or errored.
96+
You can inspect the status of any running Workflow instance by calling `status` against a specific instance ID. This allows you to programmatically inspect whether an instance is queued (waiting to be scheduled), actively running, paused, or errored.
9397

9498
```ts
9599
let instance = await env.MY_WORKFLOW.get("abc-123")
@@ -114,7 +118,7 @@ The possible values of status are as follows:
114118
};
115119
```
116120

117-
### Explicitly pausing a Workflow
121+
### Explicitly pause a Workflow
118122

119123
You can explicitly pause a Workflow instance (and later resume it) by calling `pause` against a specific instance ID.
120124

@@ -123,7 +127,7 @@ let instance = await env.MY_WORKFLOW.get("abc-123")
123127
await instance.pause() // Returns Promise<void>
124128
```
125129

126-
### Resuming a Workflow
130+
### Resume a Workflow
127131

128132
You can resume a paused Workflow instance by calling `resume` against a specific instance ID.
129133

@@ -134,7 +138,7 @@ await instance.resume() // Returns Promise<void>
134138

135139
Calling `resume` on an instance that is not currently paused will have no effect.
136140

137-
### Stopping a Workflow
141+
### Stop a Workflow
138142

139143
You can stop a Workflow instance by calling `abort` against a specific instance ID.
140144

@@ -145,7 +149,7 @@ await instance.abort() // Returns Promise<void>
145149

146150
Once stopped, the Workflow instance *cannot* be resumed.
147151

148-
### Restarting a Workflow
152+
### Restart a Workflow
149153

150154
You can restart a Workflow instance by calling `restart` against a specific instance ID.
151155

src/content/docs/workflows/build/workers-api.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ TODO
1212

1313
TODO
1414

15-
## Interacting with Workflows
15+
## Interact with Workflows
1616

1717
* Running a Workflow with the `run()` method
1818
* `StepConfig`

0 commit comments

Comments
 (0)