Skip to content

Commit 698ad8c

Browse files
ask-bonk[bot]opencode-agent[bot]elithrar
authored
Fix Workflows docs code & API errors (#28188)
* Fix Workflows docs code & API errors Co-authored-by: elithrar <elithrar@users.noreply.github.com> * Revert skills; fix changelog shadowing Co-authored-by: elithrar <elithrar@users.noreply.github.com> --------- Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: elithrar <elithrar@users.noreply.github.com>
1 parent 39ffd2d commit 698ad8c

5 files changed

Lines changed: 39 additions & 39 deletions

File tree

src/content/changelog/workflows/2025-04-07-workflows-ga.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ For example, if you wanted to implement a human-in-the-loop approval process, yo
2929
<TypeScriptExample>
3030

3131
```ts
32-
import { Workflow, WorkflowEvent } from "cloudflare:workflows";
32+
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from "cloudflare:workers";
3333

3434
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
3535
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
3636
// Other steps in your Workflow
37-
let event = await step.waitForEvent<IncomingStripeWebhook>("receive invoice paid webhook from Stripe", { type: "stripe-webhook", timeout: "1 hour" })
37+
let stripeEvent = await step.waitForEvent<IncomingStripeWebhook>("receive invoice paid webhook from Stripe", { type: "stripe-webhook", timeout: "1 hour" })
3838
// Rest of your Workflow
3939
}
4040
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ For example, to wait for billing webhook:
9292
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
9393
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
9494
// Other steps in your Workflow
95-
let event = await step.waitForEvent<IncomingStripeWebhook>(
95+
let stripeEvent = await step.waitForEvent<IncomingStripeWebhook>(
9696
"receive invoice paid webhook from Stripe",
9797
{ type: "stripe-webhook", timeout: "1 hour" },
9898
);
@@ -223,13 +223,13 @@ export class MyWorkflow extends WorkflowEntrypoint {
223223
// Pass your type as a type parameter to WorkflowEvent
224224
// The 'payload' property will have the type of your parameter.
225225
async run(event: WorkflowEvent<YourEventType>, step: WorkflowStep) {
226-
let state = step.do("my first step", async () => {
226+
let state = await step.do("my first step", async () => {
227227
// Access your properties via event.payload
228228
let userEmail = event.payload.userEmail
229229
let createdTimestamp = event.payload.createdTimestamp
230230
})
231231

232-
step.do("my second step", async () => { /* your code here */ )
232+
await step.do("my second step", async () => { /* your code here */ })
233233
}
234234
}
235235
```

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

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class MyWorkflow extends WorkflowEntrypoint {
8383
// timeout policies for each granular step - you might not to want to overload http.cat in
8484
// case of it being down.
8585
const httpCat = await step.do("get cutest cat from KV", async () => {
86-
return await env.KV.get("cutest-http-cat");
86+
return await this.env.KV.get("cutest-http-cat");
8787
});
8888

8989
const image = await step.do("fetch cat image from http.cat", async () => {
@@ -111,7 +111,7 @@ export class MyWorkflow extends WorkflowEntrypoint {
111111
// some extra calls to the first service in case the second one fails, and in some cases, makes
112112
// the step non-idempotent altogether
113113
const image = await step.do("get cutest cat from KV", async () => {
114-
const httpCat = await env.KV.get("cutest-http-cat");
114+
const httpCat = await this.env.KV.get("cutest-http-cat");
115115
return fetch(`https://http.cat/${httpCat}`);
116116
});
117117
}
@@ -142,15 +142,15 @@ export class MyWorkflow extends WorkflowEntrypoint {
142142
const imageList: string[] = [];
143143

144144
await step.do("get first cutest cat from KV", async () => {
145-
const httpCat = await env.KV.get("cutest-http-cat-1");
145+
const httpCat = await this.env.KV.get("cutest-http-cat-1");
146146

147-
imageList.append(httpCat);
147+
imageList.push(httpCat);
148148
});
149149

150150
await step.do("get second cutest cat from KV", async () => {
151-
const httpCat = await env.KV.get("cutest-http-cat-2");
151+
const httpCat = await this.env.KV.get("cutest-http-cat-2");
152152

153-
imageList.append(httpCat);
153+
imageList.push(httpCat);
154154
});
155155

156156
// A long sleep can (and probably will) hibernate the engine which means that the first engine lifetime ends here
@@ -188,11 +188,11 @@ export class MyWorkflow extends WorkflowEntrypoint {
188188
// multiple engine lifetimes, imageList will be built accordingly
189189
const imageList: string[] = await Promise.all([
190190
step.do("get first cutest cat from KV", async () => {
191-
return await env.KV.get("cutest-http-cat-1");
191+
return await this.env.KV.get("cutest-http-cat-1");
192192
}),
193193

194194
step.do("get second cutest cat from KV", async () => {
195-
return await env.KV.get("cutest-http-cat-2");
195+
return await this.env.KV.get("cutest-http-cat-2");
196196
}),
197197
]);
198198

@@ -221,7 +221,7 @@ It is not recommended to write code with any side effects outside of steps, unle
221221

222222
For example, a `console.log()` outside of workflow steps may cause the logs to print twice when the engine restarts.
223223

224-
However, logic involving non-serializable resources, like a database connection, should be executed outside of steps. Operations ouside of a `step.do` might be repeated more than once, due to the nature of the Workflows' instance lifecycle.
224+
However, logic involving non-serializable resources, like a database connection, should be executed outside of steps. Operations outside of a `step.do` might be repeated more than once, due to the nature of the Workflows' instance lifecycle.
225225

226226
<TypeScriptExample filename="index.ts">
227227

@@ -230,14 +230,14 @@ export class MyWorkflow extends WorkflowEntrypoint {
230230
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
231231
// 🔴 Bad: creating instances outside of steps
232232
// This might get called more than once creating more instances than expected
233-
const myNewInstance = await this.env.ANOTHER_WORKFLOW.create();
233+
const badInstance = await this.env.ANOTHER_WORKFLOW.create();
234234

235235
// 🔴 Bad: using non-deterministic functions outside of steps
236236
// this will produce different results if the instance has to restart, different runs of the same instance
237237
// might go through different paths
238-
const myRandom = Math.random();
238+
const badRandom = Math.random();
239239

240-
if (myRandom > 0) {
240+
if (badRandom > 0) {
241241
// do some stuff
242242
}
243243

@@ -253,21 +253,21 @@ export class MyWorkflow extends WorkflowEntrypoint {
253253

254254
// ✅ Good: wrap non-deterministic function in a step
255255
// after running successfully will not run again
256-
const myRandom = await step.do("create a random number", async () => {
256+
const goodRandom = await step.do("create a random number", async () => {
257257
return Math.random();
258258
});
259259

260260
// ✅ Good: calls that have no side effects can be done outside of steps
261261
const db = createDBConnection(this.env.DB_URL, this.env.DB_TOKEN);
262262

263-
// ✅ Good: run funtions with side effects inside of a step
263+
// ✅ Good: run functions with side effects inside of a step
264264
// after running successfully will not run again
265-
const myNewInstance = await step.do(
265+
const goodInstance = await step.do(
266266
"good step that returns state",
267267
async () => {
268-
const myNewInstance = await this.env.ANOTHER_WORKFLOW.create();
268+
const instance = await this.env.ANOTHER_WORKFLOW.create();
269269

270-
return myNewInstance;
270+
return instance;
271271
},
272272
);
273273
}
@@ -294,14 +294,14 @@ export class MyWorkflow extends WorkflowEntrypoint {
294294
// This will not be persisted across steps and `event.payload` will
295295
// take on its original value.
296296
await step.do("bad step that mutates the incoming event", async () => {
297-
let userData = await env.KV.get(event.payload.user);
297+
let userData = await this.env.KV.get(event.payload.user);
298298
event.payload = userData;
299299
});
300300

301301
// ✅ Good: persist data by returning it as state from your step
302302
// Use that state in subsequent steps
303303
let userData = await step.do("good step that returns state", async () => {
304-
return await env.KV.get(event.payload.user);
304+
return await this.env.KV.get(event.payload.user);
305305
});
306306

307307
let someOtherData = await step.do(
@@ -329,16 +329,16 @@ export class MyWorkflow extends WorkflowEntrypoint {
329329
// 🔴 Bad: Naming the step non-deterministically prevents it from being cached
330330
// This will cause the step to be re-run if subsequent steps fail.
331331
await step.do(`step #1 running at: ${Date.now()}`, async () => {
332-
let userData = await env.KV.get(event.payload.user);
332+
let userData = await this.env.KV.get(event.payload.user);
333333
// Do not mutate event.payload
334334
event.payload = userData;
335335
});
336336

337337
// ✅ Good: give steps a deterministic name.
338338
// Return dynamic values in your state, or log them instead.
339339
let state = await step.do("fetch user data from KV", async () => {
340-
let userData = await env.KV.get(event.payload.user);
341-
console.log(`fetched at ${Date.now}`);
340+
let userData = await this.env.KV.get(event.payload.user);
341+
console.log(`fetched at ${Date.now()}`);
342342
return userData;
343343
});
344344

@@ -347,12 +347,12 @@ export class MyWorkflow extends WorkflowEntrypoint {
347347
// traversed in a deterministic fashion (no shuffles or random accesses) so,
348348
// it's fine to dynamically name steps (e.g: create a step per list entry).
349349
let catList = await step.do("get cat list from KV", async () => {
350-
return await env.KV.get("cat-list");
350+
return await this.env.KV.get("cat-list");
351351
});
352352

353353
for (const cat of catList) {
354354
await step.do(`get cat: ${cat}`, async () => {
355-
return await env.KV.get(cat);
355+
return await this.env.KV.get(cat);
356356
});
357357
}
358358
}
@@ -490,14 +490,14 @@ This happens when you do not use the `await` keyword or fail to chain `.then()`
490490
export class MyWorkflow extends WorkflowEntrypoint {
491491
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
492492
// 🔴 Bad: The step isn't await'ed, and any state or errors is swallowed before it returns.
493-
const issues = step.do(`fetch issues from GitHub`, async () => {
493+
const badIssues = step.do(`fetch issues from GitHub`, async () => {
494494
// The step will return before this call is done
495495
let issues = await getIssues(event.payload.repoName);
496496
return issues;
497497
});
498498

499499
// ✅ Good: The step is correctly await'ed.
500-
const issues = await step.do(`fetch issues from GitHub`, async () => {
500+
const goodIssues = await step.do(`fetch issues from GitHub`, async () => {
501501
let issues = await getIssues(event.payload.repoName);
502502
return issues;
503503
});
@@ -557,7 +557,7 @@ export class MyWorkflow extends WorkflowEntrypoint {
557557

558558
### Batch multiple Workflow invocations
559559

560-
When creating multiple Workflow instances, use the [`createBatch`](/workflows/build/workers-api/#createBatch) method to batch the invocations together. This allows you to create multiple Workflow instances in a single request, which will reduce the number of requests made to the Workflows API. However, each individual instance in the batch will still count towards the [creation rate limit](/workflows/reference/limits/).
560+
When creating multiple Workflow instances, use the [`createBatch`](/workflows/build/workers-api/#createBatch) method to batch the invocations together. This allows you to create multiple Workflow instances in a single request, which will reduce the number of requests made to the Workflows API. However, each individual instance in the batch will still count towards the [creation rate limit](/workflows/reference/limits/). Unlike `create`, `createBatch` is idempotent: if an existing instance with the same ID is still within its [retention limit](/workflows/reference/limits/), it will be skipped and excluded from the returned array.
561561

562562
<TypeScriptExample filename="index.ts">
563563

@@ -581,8 +581,8 @@ export default {
581581

582582
// ✅ Good: Batch calls together
583583
// This improves throughput.
584-
let instances = await env.MY_WORKFLOW.createBatch(instances);
585-
return Response.json({ instances });
584+
let createdInstances = await env.MY_WORKFLOW.createBatch(instances);
585+
return Response.json({ instances: createdInstances });
586586
},
587587
};
588588
```

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ When providing your own `StepConfig`, you can configure:
7777
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`:
7878

7979
```ts
80-
let someState = step.do("call an API", {
80+
let someState = await step.do("call an API", {
8181
retries: {
8282
limit: 10, // The total number of attempts
8383
delay: "10 seconds", // Delay between each retry
8484
backoff: "exponential" // Any of "constant" | "linear" | "exponential";
8585
},
8686
timeout: "30 minutes",
87-
}, async () => { /* Step code goes here /* }
87+
}, async () => { /* Step code goes here */ })
8888
```
8989

9090
## Force a Workflow instance to fail
@@ -132,7 +132,7 @@ try {
132132
// work not to be retried
133133
throw new NonRetryableError('oh no');
134134
});
135-
} catch(e as Error) {
135+
} catch (e) {
136136
console.log(`Step failed: ${e.message}`);
137137
await step.do('clean-up-task', async () => {
138138
// Clean up code here

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Objects that include `Function` or `Symbol` types, and objects with circular ref
102102
{/* prettier-ignore */}
103103
- <code>step.sleepUntil(name: string, timestamp: Date | number): Promise&lt;void&gt;</code>
104104
- `name` - the name of the step.
105-
- `timestamp` - a JavaScript `Date` object or seconds from the Unix epoch to sleep the Workflow instance until.
105+
- `timestamp` - a JavaScript `Date` object or milliseconds from the Unix epoch to sleep the Workflow instance until.
106106

107107
:::note
108108

@@ -122,7 +122,7 @@ More information about the limits imposed on Workflow can be found in the [Workf
122122
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
123123
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
124124
// Other steps in your Workflow
125-
let event = await step.waitForEvent<IncomingStripeWebhook>(
125+
let stripeEvent = await step.waitForEvent<IncomingStripeWebhook>(
126126
"receive invoice paid webhook from Stripe",
127127
{ type: "stripe-webhook", timeout: "1 hour" },
128128
);

0 commit comments

Comments
 (0)