Control Flow Patterns
Common distributed control flow patterns are really simple to implement in workflows and require learning no new syntax. You can just use familiar async/await patterns.
Sequential Execution
The simplest way to orchestrate steps is to execute them one after another, where each step can be dependent on the previous step.
export async function dataPipelineWorkflow(data: any) {
"use workflow";
const validated = await validateData(data);
const processed = await processData(validated);
const stored = await storeData(processed);
return stored;
}Parallel Execution
When needing to execute multiple steps in parallel, you can use Promise.all to run them all at the same time.
export async function fetchUserData(userId: string) {
"use workflow";
const [user, orders, preferences] = await Promise.all([
fetchUser(userId),
fetchOrders(userId),
fetchPreferences(userId)
]);
return { user, orders, preferences };
}This not only applies to steps - since sleep() and webhook are also just promises, we can await those in parallel too.
We can also use Promise.race instead of Promise.all to stop executing the promises after the first one completes.
import { sleep, createWebhook } from "workflow";
export async function runExternalTask(userId: string) {
"use workflow";
const webhook = createWebhook();
await executeExternalTask(webhook.url); // Send the webhook somewhere
// Wait for the external webhook to hit, with a timeout of 1 day,
// whichever comes first
await Promise.race([
webhook,
sleep('1 day'),
]);
console.log("Done")
}A full example
Here's a simplified example taken from the birthday card generator demo, to illustrate how more complex orchestration can be modelled in promises.
import { createWebhook, sleep } from "workflow"
async function birthdayWorkflow(
prompt: string,
email: string,
friends: string[],
birthday: Date
) {
"use workflow";
// Generate a birthday card with sequential steps
const text = await makeCardText(prompt)
const image = await makeCardImage(text)
// Create webhooks for each friend who's invited to the birthday party
const webhooks = friends.map(_ => createWebhook())
// Send out all the RSVP invites in parallel steps
await Promise.all(
friends.map(
(friend, i) => sendRSVPEmail(friend, webhooks[i])
)
)
// Collect RSVPs as they are made without blocking the workflow
let rsvps = []
webhooks.map(
webhook => webhook
.then(req => req.json())
.then(( { rsvp } ) => rsvps.push(rsvp))
)
// Wait until the birthday
await sleep(birthday)
// Send birthday card with as many rsvps were collected
await sendBirthdayCard(text, image, rsvps, email)
return { text, image, status: "Sent" }
}