@roostjs/workflow
Durable multi-step workflows on Cloudflare Workflows. Workflow base class, WorkflowClient, Compensable, and service provider.
Installation
bun add @roostjs/workflowConfiguration
Declare a Cloudflare Workflow binding in wrangler.jsonc:
{
"workflows": [
{
"name": "my-workflow",
"binding": "MY_WORKFLOW",
"class_name": "MyWorkflow"
}
]
}Workflow API
Workflow<Env, TParams> is an abstract base class that extends Cloudflare's
WorkflowEntrypoint. Implement run() and register the class with
WorkflowServiceProvider.
Instance Methods
abstract async run(event: WorkflowEvent<TParams>, step: WorkflowStep): Promise<unknown>
The workflow's main logic. event.payload contains the typed params passed at
creation. Use step.do() for durable operations and step.sleep() for delays.
Cloudflare Workflows re-runs run() from the start on retry; each step.do()
call is replayed from the checkpoint cache rather than re-executed.
Static Methods
static fake(): void
Enable fake mode. WorkflowClient.create() calls are recorded but not sent to
Cloudflare.
static restore(): void
Disable fake mode and remove the stored fake.
static assertCreated(id?: string): void
Assert that the workflow was created (in fake mode). Pass an id to assert a
specific instance was created.
static assertNotCreated(): void
Assert that no workflow instance was created.
static _getFake(): WorkflowFake | undefined
Internal. Returns the active fake for this class, if any.
WorkflowClient API
WorkflowClient<TParams> wraps a Cloudflare Workflow binding and returns
typed WorkflowInstanceHandle objects.
constructor(binding: Workflow<TParams>)
Construct with the raw Cloudflare Workflow binding from the env.
async create(params: WorkflowCreateParams<TParams>): Promise<WorkflowInstanceHandle>
Create a new workflow instance. If params.id is omitted, Cloudflare generates one.
async get(id: string): Promise<WorkflowInstanceHandle>
Retrieve an existing workflow instance by ID.
async terminate(id: string): Promise<void>
Terminate a running workflow instance.
WorkflowInstanceHandle API
Returned by WorkflowClient.create() and WorkflowClient.get().
id: string
The unique identifier of the workflow instance.
async pause(): Promise<void>
Pause execution of the workflow instance.
async resume(): Promise<void>
Resume a paused workflow instance.
async abort(reason?: string): Promise<void>
Terminate the workflow instance with an optional reason string.
async status(): Promise<WorkflowInstanceStatus>
Fetch the current status of the instance.
Compensable API
Compensable is a helper for saga-style rollback. Register compensation
functions during workflow execution; if a step fails, call compensate() to
undo previous operations in reverse order.
register(compensation: CompensationFn): void
Register a compensation function. Compensations are called last-registered-first on rollback.
async compensate(): Promise<void>
Execute all registered compensations in reverse order. Each compensation is called with best-effort: if one throws, the error is swallowed and execution continues to the next. The compensation list is cleared after running.
WorkflowServiceProvider API
Registers workflow classes with the service container so they can be resolved by their binding name.
withWorkflows(workflows: Array<{ workflowClass: typeof Workflow; binding: string }>): this
Chain one or more workflow registrations. Each entry maps a Workflow subclass
to its Cloudflare binding name.
register(): void
Called by the service container bootstrap. Resolves bindings from the env and
registers WorkflowClient instances (or fakes) under the key
workflow:{ClassName}.
Types
interface WorkflowCreateParams<TParams = unknown> {
id?: string;
params: TParams;
}
interface WorkflowInstanceHandle {
id: string;
pause(): Promise<void>;
resume(): Promise<void>;
abort(reason?: string): Promise<void>;
status(): Promise<WorkflowInstanceStatus>;
}
type WorkflowInstanceStatus = {
status: 'queued' | 'running' | 'paused' | 'complete' | 'errored' | 'terminated';
output?: unknown;
error?: string;
};Errors
WorkflowError
Base error class for workflow-related failures. Accepts an optional workflowId
property for correlation.
class WorkflowError extends Error {
constructor(message: string, workflowId?: string);
readonly workflowId?: string;
}NonRetryableError
Re-exported from cloudflare:workflows. Throw inside run() to signal a
permanent failure that should not be retried.
Testing
WorkflowFake
Internal fake state object managed by Workflow.fake(). Accessible via
Workflow._getFake() for advanced assertions.
interface FakeWorkflowRecord {
id: string;
params: unknown;
createdAt: Date;
}
class WorkflowFake {
created: FakeWorkflowRecord[];
recordCreate(id: string, params: unknown): void;
assertCreated(id?: string): void;
assertNotCreated(): void;
}