Skip to content

Commit 033725b

Browse files
avenceslaumia303
andauthored
warn users to avoid side effects top level (cloudflare#26431)
* warn users to avoid side effects top level * add ; and change ' to " * add awaits * make text clearer * Update rules-of-workflows.mdx --------- Co-authored-by: mia303 <[email protected]>
1 parent 3f87b12 commit 033725b

File tree

1 file changed

+58
-0
lines changed

1 file changed

+58
-0
lines changed

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,64 @@ export class MyWorkflow extends WorkflowEntrypoint {
205205
```
206206
</TypeScriptExample>
207207

208+
### Avoid doing side effects outside of a `step.do`
209+
210+
It is not recommended to write code with any side effects outside of steps, unless you would like it to be repeated, because the Workflow engine may restart while an instance is running. If the engine restarts, the step logic will be preserved, but logic outside of the steps may be duplicated.
211+
212+
For example, a `console.log()` outside of workflow steps may cause the logs to print twice when the engine restarts.
213+
214+
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.
215+
216+
<TypeScriptExample filename="index.ts">
217+
```ts
218+
export class MyWorkflow extends WorkflowEntrypoint {
219+
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
220+
// 🔴 Bad: creating instances outside of steps
221+
// This might get called more than once creating more instances than expected
222+
const myNewInstance = await this.env.ANOTHER_WORKFLOW.create();
223+
224+
// 🔴 Bad: using non-deterministic functions outside of steps
225+
// this will produce different results if the instance has to restart, different runs of the same instance
226+
// might go through different paths
227+
const myRandom = Math.random();
228+
229+
if(myRandom > 0) {
230+
// do some stuff
231+
}
232+
233+
// ⚠️ Warning: This log may happen many times
234+
console.log("This might be logged more than once");
235+
236+
await step.do("do some stuff and have a log for when it runs", async () => {
237+
// do some stuff
238+
239+
// this log will only appear once
240+
console.log("successfully did stuff");
241+
})
242+
243+
244+
// ✅ Good: wrap non-deterministic function in a step
245+
// after running successfully will not run again
246+
const myRandom = await step.do("create a random number", async () => {
247+
return Math.random();
248+
})
249+
250+
// ✅ Good: calls that have no side effects can be done outside of steps
251+
const db = createDBConnection(this.env.DB_URL, this.env.DB_TOKEN);
252+
253+
// ✅ Good: run funtions with side effects inside of a step
254+
// after running successfully will not run again
255+
const myNewInstance = await step.do("good step that returns state", async () => {
256+
const myNewInstance = await this.env.ANOTHER_WORKFLOW.create();
257+
258+
return myNewInstance;
259+
})
260+
}
261+
}
262+
```
263+
</TypeScriptExample>
264+
265+
208266
### Do not mutate your incoming events
209267

210268
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.

0 commit comments

Comments
 (0)