cloudflare-workflows
π―Skillfrom itechmeat/llm-code
Orchestrates multi-step, durable cloud workflows with state persistence, retries, scheduling, and external event handling using Cloudflare Workers.
Part of
itechmeat/llm-code(31 items)
Installation
npx wrangler deploySkill Details
"Cloudflare Workflows durable execution playbook: multi-step orchestration, state persistence, retries, sleep/scheduling, waitForEvent, external events, bindings, lifecycle management, limits, pricing. Keywords: Cloudflare Workflows, durable execution, WorkflowEntrypoint, step.do, step.sleep, waitForEvent, sendEvent, retries, NonRetryableError, Workflow binding."
Overview
# Cloudflare Workflows
Workflows provide durable multi-step execution for Workers. Steps persist state, survive restarts, support retries, and can sleep for days.
---
Quick Start
Create Workflow
```typescript
// src/index.ts
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from "cloudflare:workers";
interface Env {
MY_WORKFLOW: Workflow;
}
interface Params {
userId: string;
action: string;
}
export class MyWorkflow extends WorkflowEntrypoint
async run(event: WorkflowEvent
const user = await step.do("fetch user", async () => {
const resp = await fetch(https://api.example.com/users/${event.payload.userId});
return resp.json();
});
await step.sleep("wait before processing", "1 hour");
const result = await step.do("process action", async () => {
return { processed: true, user: user.id };
});
return result; // Available in instance.status().output
}
}
export default {
async fetch(request: Request, env: Env): Promise
const instance = await env.MY_WORKFLOW.create({
params: { userId: "123", action: "activate" },
});
return Response.json({ instanceId: instance.id });
},
};
```
wrangler.jsonc
```jsonc
{
"name": "my-workflow-worker",
"main": "src/index.ts",
"workflows": [
{
"name": "my-workflow",
"binding": "MY_WORKFLOW",
"class_name": "MyWorkflow"
}
]
}
```
Deploy
```bash
npx wrangler deploy
```
---
Core Concepts
WorkflowEntrypoint
```typescript
export class MyWorkflow extends WorkflowEntrypoint
async run(event: WorkflowEvent
// Workflow logic with steps
return optionalResult;
}
}
```
WorkflowEvent
```typescript
interface WorkflowEvent
payload: Readonly
timestamp: Date; // Creation time
instanceId: string; // Unique instance ID
}
```
Warning: Event payload is immutable. Changes are NOT persisted across steps. Return state from steps instead.
WorkflowStep
```typescript
interface WorkflowStep {
do
do
sleep(name: string, duration: Duration): Promise
sleepUntil(name: string, timestamp: Date | number): Promise
waitForEvent
}
```
See [api.md](references/api.md) for full type definitions.
---
Steps
Basic Step
```typescript
const result = await step.do("step name", async () => {
const response = await fetch("https://api.example.com/data");
return response.json(); // State persisted
});
```
Step with Config
```typescript
const data = await step.do(
"call external API",
{
retries: {
limit: 10,
delay: "30 seconds",
backoff: "exponential",
},
timeout: "5 minutes",
},
async () => {
return await externalApiCall();
}
);
```
Default Step Config
```typescript
const defaultConfig = {
retries: {
limit: 5,
delay: 10000, // 10 seconds
backoff: "exponential",
},
timeout: "10 minutes",
};
```
| Option | Type | Default | Description |
| ----------------- | ------------- | ----------- | ------------------------------------------- |
| retries.limit | number | 5 | Max attempts (use Infinity for unlimited) |
| retries.delay | string/number | 10000 | Delay between retries |
| retries.backoff | string | exponential | constant, linear, exponential |
| timeout | string/number | 10 min | Per-attempt timeout |
---
Sleep & Scheduling
Relative Sleep
```typescript
await step.sleep("wait before retry", "1 hour");
await step.sleep("short pause", 5000); // 5 seconds (ms)
```
Duration units: second, minute, hour, day, week, month, year.
Sleep Until Date
```typescript
const targetDate = new Date("2024-12-31T00:00:00Z");
await step.sleepUntil("wait until new year", targetDate);
// Or with timestamp
await step.sleepUntil("wait until launch", Date.parse("24 Oct 2024 13:00:00 UTC"));
```
Maximum sleep: 365 days.
Note: step.sleep and step.sleepUntil do NOT count towards the 1024 steps limit.
---
Wait for Events
Wait in Workflow
```typescript
const approval = await step.waitForEvent<{ approved: boolean }>("wait for approval", {
type: "user_approval",
timeout: "7 days",
});
if (approval.approved) {
await step.do("proceed", async () => {
/ ... /
});
}
```
Default timeout: 24 hours.
Timeout behavior: Throws error and fails instance. Use try-catch to continue:
```typescript
try {
const event = await step.waitForEvent("optional event", { type: "update", timeout: "1 hour" });
} catch (e) {
// Continue without event
}
```
Send Event from Worker
```typescript
export default {
async fetch(request: Request, env: Env): Promise
const { instanceId, approved } = await request.json();
const instance = await env.MY_WORKFLOW.get(instanceId);
await instance.sendEvent({
type: "user_approval", // Must match waitForEvent type
payload: { approved },
});
return new Response("Event sent");
},
};
```
Event buffering: Events can be sent before Workflow reaches waitForEvent. They are buffered and delivered when the matching step executes.
See [events.md](references/events.md) for REST API.
---
Error Handling
NonRetryableError
```typescript
import { NonRetryableError } from "cloudflare:workflows";
await step.do("validate input", async () => {
if (!event.payload.data) {
throw new NonRetryableError("Missing required data");
}
return event.payload.data;
});
```
Catch and Continue
```typescript
try {
await step.do("risky operation", async () => {
await riskyApiCall();
});
} catch (error) {
await step.do("handle failure", async () => {
await sendAlertEmail(error.message);
});
}
```
Workflow States
| Status | Description |
| ----------------- | ------------------------------------------ |
| queued | Waiting to start |
| running | Actively executing |
| paused | Manually paused |
| waiting | Sleeping or waiting for event |
| waitingForPause | Pause requested, waiting to take effect |
| complete | Successfully finished |
| errored | Failed (uncaught exception or retry limit) |
| terminated | Manually terminated |
---
Workflow Bindings
Create Instance
```typescript
const instance = await env.MY_WORKFLOW.create({
id: "order-12345", // Optional custom ID (max 100 chars)
params: { orderId: 12345 },
});
console.log(instance.id);
```
Create Batch
```typescript
const instances = await env.MY_WORKFLOW.createBatch([{ params: { userId: "1" } }, { params: { userId: "2" } }, { params: { userId: "3" } }]);
// Up to 100 instances per batch
```
Get Instance
```typescript
const instance = await env.MY_WORKFLOW.get("order-12345");
```
Instance Methods
```typescript
await instance.pause(); // Pause execution
await instance.resume(); // Resume paused
await instance.terminate(); // Stop permanently
await instance.restart(); // Restart from beginning
const status = await instance.status();
console.log(status.status); // "running", "complete", etc.
console.log(status.output); // Return value from run()
console.log(status.error); // { name, message } if errored
await instance.sendEvent({
type: "approval",
payload: { approved: true },
});
```
---
Rules of Workflows
β DO
- Make steps granular and self-contained
- Return state from steps (only way to persist)
- Name steps deterministically
awaitall step calls- Keep step return values under 1 MiB
- Use idempotent operations in steps
- Base conditions on
event.payloador step returns
β DON'T
- Store state outside steps (lost on restart)
- Mutate
event.payload(changes not persisted) - Use non-deterministic step names (
Date.now(),Math.random()) - Skip
awaiton step calls - Put entire logic in one step
- Call multiple unrelated services in one step
- Do heavy CPU work in single step
Step State Persistence
```typescript
// β Good: Return state from step
const userData = await step.do("fetch user", async () => {
return await fetchUser(userId);
});
// β Bad: State stored outside step (lost on restart)
let userData;
await step.do("fetch user", async () => {
userData = await fetchUser(userId); // Will be lost!
});
```
---
Wrangler Commands
```bash
# List instances
wrangler workflows instances list my-workflow
# Describe instance
wrangler workflows instances describe my-workflow --id
# Terminate instance
wrangler workflows instances terminate my-workflow --id
# Trigger new instance
wrangler workflows trigger my-workflow --params '{"key": "value"}'
# Delete Workflow
wrangler workflows delete my-workflow
```
---
Limits
| Feature | Free | Paid |
| ------------------------ | --------- | ------------------ |
| CPU time per step | 10 ms | 30 sec (max 5 min) |
| Wall clock per step | Unlimited | Unlimited |
| State per step | 1 MiB | 1 MiB |
| Event payload | 1 MiB | 1 MiB |
| Total state per instance | 100 MB | 1 GB |
| Max sleep duration | 365 days | 365 days |
| Max steps per Workflow | 1024 | 1024 |
| Concurrent instances | 25 | 10,000 |
| Instance creation rate | 100/sec | 100/sec |
| Queued instances | 100,000 | 1,000,000 |
| Subrequests per instance | 50/req | 1000/req |
| Instance ID length | 100 chars | 100 chars |
| Retention (completed) | 3 days | 30 days |
Note: Instances in waiting state (sleeping, waiting for event) do NOT count against concurrency limits.
Increase CPU Limit
```jsonc
{
"limits": {
"cpu_ms": 300000 // 5 minutes
}
}
```
---
Pricing
Based on Workers Standard pricing:
| Metric | Free | Paid |
| -------- | ----------------- | ------------------------------- |
| Requests | 100K/day (shared) | 10M/mo included, +$0.30/M |
| CPU time | 10 ms/invocation | 30M ms/mo included, +$0.02/M ms |
| Storage | 1 GB | 1 GB included, +$0.20/GB-mo |
Storage notes:
- Calculated across all instances (running, sleeping, completed)
- Deleting instances frees storage (updates within minutes)
- Free plan: instance errors if storage limit reached
See [pricing.md](references/pricing.md) for details.
---
Prohibitions
- β Do not mutate
event.payload(changes not persisted) - β Do not store state outside steps
- β Do not use non-deterministic step names
- β Do not exceed 1 MiB per step return
- β Do not skip
awaiton step calls - β Do not rely on in-memory state between steps
---
References
- [api.md](references/api.md) β Full API reference
- [events.md](references/events.md) β Event handling and REST API
- [patterns.md](references/patterns.md) β Saga, approval, reminders
- [pricing.md](references/pricing.md) β Billing details
Cross-References (Skills)
cloudflare-workersβ Worker developmentcloudflare-queuesβ Message queue integrationcloudflare-r2β Large state storagecloudflare-kvβ Key-value references
More from this repository10
skill-master skill from itechmeat/llm-code
react-testing-library skill from itechmeat/llm-code
commits skill from itechmeat/llm-code
changelog skill from itechmeat/llm-code
social-writer skill from itechmeat/llm-code
project-creator skill from itechmeat/llm-code
Runs fast, Vite-powered tests with Jest-compatible API, supporting TypeScript, mocking, and browser testing out of the box.
coderabbit skill from itechmeat/llm-code
Accelerates frontend development by providing a lightning-fast build tool with instant server startup, hot module replacement, and flexible configuration.
openspec skill from itechmeat/llm-code