Overview
This example demonstrates BlueLibs Runner’s Durable Workflows feature - a powerful way to build long-running, multi-step processes that can:- Survive restarts - Workflow state persists between crashes
- Wait for external signals - Pause until external events arrive (webhooks, user actions)
- Handle timeouts - Branch logic based on whether signals arrive in time
- Replay safely - Non-deterministic operations are memoized automatically
- Order Processing - Payment flow with signal-based confirmation
- User Onboarding - Multi-step onboarding with email verification and timeout handling
What Are Durable Workflows?
Durable workflows are tasks that execute as a series of steps. Each step’s result is persisted, making the workflow resilient to:- Process crashes
- Server restarts
- Network failures
- Long delays (hours, days, weeks)
- Waiting for payment confirmation
- Waiting for user email verification
- Waiting for admin approval
- Multi-day onboarding flows
Architecture
The example demonstrates:- ctx.step() - Define durable steps with automatic memoization
- ctx.sleep() - Durable sleep that survives restarts
- ctx.waitForSignal() - Pause until external signal arrives
- ctx.switch() - Replay-safe branching based on runtime values
- ctx.note() - Add audit trail entries
Key Code Snippets
Workflow 1: Order Processing
orderProcessing.ts
Workflow 2: User Onboarding
userOnboarding.ts
Running Workflows
How to Run
Workflow Features
| Feature | API | Example |
|---|---|---|
| Durable steps | ctx.step(id, fn) | Order processing, user onboarding |
| Durable sleep | ctx.sleep(ms) | Order processing (100ms delay) |
| Wait for signals | ctx.waitForSignal(signal) | Payment confirmation |
| Signals with timeout | ctx.waitForSignal(signal, { timeoutMs }) | Email verification (15s timeout) |
| Replay-safe branching | ctx.switch(id, value, branches) | Provision workspace only if verified |
| Audit trail | ctx.note(message) | Log important events |
| Start workflow | service.start(task, input) | Begin order processing |
| Send signal | service.signal(execId, signal, payload) | Confirm payment |
| Wait for completion | service.wait(execId, options) | Get final result |
What to Learn
1. Durable Steps
Each step’s result is persisted. If the workflow crashes and restarts, completed steps are not re-executed:2. Signals for External Events
Workflows can pause and wait for external events:- Payment gateway callbacks
- User actions (email clicks, form submissions)
- Admin approvals
- External system integrations
3. Timeouts
Signals can have timeouts for fallback logic:4. Replay-Safe Branching
ctx.switch() ensures branches are deterministic across replays:
5. Audit Trail
Usectx.note() to record important events:
6. State Persistence
The example uses an in-memory store for simplicity. In production, use a persistent store:7. Use Cases
Durable workflows are perfect for:- E-commerce: Order processing, payment flows, fulfillment
- Onboarding: Multi-step user setup with email/SMS verification
- Approvals: Workflows requiring manual approval steps
- Integrations: Long-running data sync or API orchestration
- Scheduling: Multi-day campaigns or reminder sequences