Workflows
State Management
Last updated March 3, 2026
How Cencori persists workflow state, handles retries, and ensures idempotency.
One of the hardest parts of building agentic systems is State. What happens if your server crashes while the LLM is thinking? What happens if a webhook is delivered twice?
Cencori handles this automatically.
The State Object
Every workflow execution has a persistent JSON state object.
// Initial State
{
"step": "init",
"data": {}
}When you call cencori.steps.run(), we:
- Check if this step has already run.
- If yes, return the cached result (Idempotency).
- If no, run it and save the result to state.
Idempotency Keys
Triggers are idempotent by default if you provide an id.
// If you send this twice, Cencori only runs it once.
cencori.workflows.trigger('signup-flow', { userId: '123' }, {
idempotencyKey: 'signup-123'
});Durable Execution
If your Node.js server restarts mid-workflow, Cencori's SDK (when using the Cloud Runner) or your self-hosted worker picks up exactly where it left off.
- Completed Steps: Skipped (cached).
- Pending Steps: Retried.
Race Conditions
When multiple events hit the same workflow (e.g. waitFor), Cencori serializes the updates to the State object to prevent race conditions.
sequenceDiagram
Event A->>Workflow: Update State (Lock)
Event B->>Workflow: Wait for Lock
Workflow->>Event A: Ack
Event B->>Workflow: Update StateBest Practices
- Deterministic Steps: Ensure your steps produce the same output for the same input (or cache them).
- Small State: Don't store 100MB PDFs in the workflow state. Store the URL to S3 instead.
- Versioning: If you change your workflow code, existing executions might break. Use
v1,v2naming for critical flows.