Skip to content

Commit 9c054b8

Browse files
committed
fix
1 parent 6d2439f commit 9c054b8

File tree

1 file changed

+19
-15
lines changed

1 file changed

+19
-15
lines changed

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

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
---
2-
title: Rules of Steps
2+
title: Rules of Workflows
33
pcx_content_type: concept
44
sidebar:
55
order: 10
66
---
77

8-
A Workflow step is 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. A Workflow is comprised of one or more steps.
99

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

@@ -18,8 +18,8 @@ As an example, let's assume you have a Workflow that charges your customers and
1818
check if they were already charged:
1919

2020
```ts
21-
export class MyWorkflow extends Workflow<Env, Params> {
22-
async run(events: WorkflowEvent[], step: WorkflowStep) {
21+
export class MyWorkflow extends WorkflowEntrypoint {
22+
async run(event: WorkflowEvent, step: WorkflowStep) {
2323
const customer_id = 123456;
2424
// ✅ Good: Non-idempotent API/Binding calls are always done **after** checking if the operation is
2525
// still needed.
@@ -55,20 +55,21 @@ export class MyWorkflow extends Workflow<Env, Params> {
5555

5656
:::note
5757

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

6060
:::
6161

6262
### Make your steps granular
6363

6464
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.
65+
6566
You can also think of it as a transaction, or a unit of work.
6667

6768
- ✅ Minimize the number of API/binding calls per step (unless you need multiple calls to prove idempotency).
6869

6970
```ts
70-
export class MyWorkflow extends Workflow<Env, Params> {
71-
async run(events: WorkflowEvent[], step: WorkflowStep) {
71+
export class MyWorkflow extends WorkflowEntrypoint {
72+
async run(event: WorkflowEvent, step: WorkflowStep) {
7273
// ✅ Good: Unrelated API/Binding calls are self-contained, so that in case one of them fails
7374
// it can retry them individually. It also has an extra advantage: you can control retry or
7475
// timeout policies for each granular step - you might not to want to overload http.cat in
@@ -92,8 +93,8 @@ Otherwise your entire workflow might not be as durable as you might think, and e
9293
- 🔴 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.
9394

9495
```ts
95-
export class MyWorkflow extends Workflow<Env, Params> {
96-
async run(events: WorkflowEvent[], step: WorkflowStep) {
96+
export class MyWorkflow extends WorkflowEntrypoint {
97+
async run(event: WorkflowEvent, step: WorkflowStep) {
9798
// 🔴 Bad: you're calling two seperate services from within the same step. This might cause
9899
// some extra calls to the first service in case the second one fails, and in some cases, makes
99100
// the step non-idempotent altogether
@@ -107,8 +108,9 @@ export class MyWorkflow extends Workflow<Env, Params> {
107108

108109
### Don't rely on state outside of a step
109110

110-
Sometimes, our Engine will hibernate and lose all in-memory state - this will happen when engine detects that there's no pending work and can hibernate
111-
until it needs to wake-up (because of a sleep, retry or event). This means that you can't do something like this:
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).
112+
113+
This means that you should not store state outside of a step:
112114

113115
```ts
114116
function getRandomInt(min, max) {
@@ -117,8 +119,8 @@ function getRandomInt(min, max) {
117119
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); // The maximum is exclusive and the minimum is inclusive
118120
}
119121

120-
export class MyWorkflow extends Workflow<Env, Params> {
121-
async run(events: WorkflowEvent[], step: WorkflowStep) {
122+
export class MyWorkflow extends WorkflowEntrypoint {
123+
async run(event: WorkflowEvent, step: WorkflowStep) {
122124
// 🔴 Bad: `imageList` will be not persisted across engine's lifetimes. Which means that after hibernation,
123125
// `imageList` will be empty again, even though the following two steps have already ran.
124126
const imageList: string[] = [];
@@ -160,8 +162,8 @@ function getRandomInt(min, max) {
160162
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled); // The maximum is exclusive and the minimum is inclusive
161163
}
162164

163-
export class MyWorkflow extends Workflow<Env, Params> {
164-
async run(events: WorkflowEvent[], step: WorkflowStep) {
165+
export class MyWorkflow extends WorkflowEntrypoint {
166+
async run(event: WorkflowEvent, step: WorkflowStep) {
165167
// ✅ Good: imageList state is exclusively comprised of step returns - this means that in the event of
166168
// multiple engine lifetimes, imageList will be built accordingly
167169
const imageList: string[] = await Promise.all([
@@ -200,3 +202,5 @@ TODO
200202
TODO
201203

202204
### Don't mutate your incoming events
205+
206+
TODO

0 commit comments

Comments
 (0)