Durable Execution
Causet sagas are durable by construction. Saga state lives in the entity snapshot, which is persisted to PostgreSQL by the causet-projection-worker. A runtime restart doesn’t lose saga state — the next intent against that entity reads the persisted snapshot and resumes from the correct step.
What Durability Means in Causet
When an entity is mid-saga and the causet-runtime-service restarts:
- In-flight intents may fail (their callers receive errors)
- Events already committed to the ledger are not lost
- The entity snapshot reflects the last successfully processed event
- The next intent submitted to that entity reads the persisted snapshot
The saga resumes from wherever it was. No saga step is re-run twice because step advancement is event-driven: a step only fires when the corresponding event is committed, and events are written at-most-once to the ledger.
Why This Differs from Temporal
Temporal provides durable execution through workflow history replay: the workflow function re-executes from the beginning, skipping already-completed activities. Causet does not do this.
| Capability | Causet Sagas | Temporal |
|---|---|---|
| State persistence | Entity snapshot | Workflow history |
| Durability | Event-driven, step-level | Function replay, activity-level |
| Restart behavior | Resume from snapshot | Replay full workflow |
| Activity retries | Not supported | Built-in with backoff |
| External signals | Not supported | Built-in |
| Long sleeps | Limited (delay_seconds) | Arbitrary duration timers |
| Compensation | Not built-in | Saga compensations |
Causet sagas are simpler and more constrained. They are the right tool when your workflow is entirely event-driven and each step maps to a domain event in your ledger.
Saga Replay from Ledger
Because all entity state is derived from ledger events and rules are deterministic, sagas can be replayed from scratch. Replaying the ledger_events table through the rules engine will reproduce the exact saga state at any point in time.
This is useful for:
- Debugging saga transitions
- Auditing what happened during a process
- Rebuilding entity snapshots after a schema change
Note: Replay does not re-fire side effects by default.
op: submitandop: scheduleoperations do not execute during snapshot rebuild. This is correct behavior — you don’t want to re-send emails or re-trigger downstream services when rebuilding state.
Limitations
Short-Delay Timers Only
op: schedule supports delay_seconds — a relative offset from intent processing time. This is suitable for delays up to a few hours or days.
For delays measured in weeks or months, use an external scheduler (cron, EventBridge, etc.) that submits an intent to Causet when the delay expires:
External Scheduler ──(fire at T+30d)──► submit SHOW_ANNIVERSARY_REMINDER to CausetThe entity stays in its current saga step indefinitely — it doesn’t time out. The scheduler is responsible for re-activating it.
No Built-in Timeout
Sagas do not have built-in step timeouts. An entity can stay in a non-terminal saga step forever. To detect stalls, monitor saga state via projections:
SELECT import_id, current_step, last_updated_at
FROM import_pipeline_status
WHERE current_step BETWEEN 1 AND 3
AND last_updated_at < extract(epoch from (now() - interval '2 hours')) * 1000
ORDER BY last_updated_at ASC;Alert on this query result and submit a corrective intent or escalation event when the threshold is exceeded.
No Automatic Compensation
If a saga reaches a failed step, Causet does not automatically undo prior steps. Compensation (rollback) must be modeled explicitly: define a reset intent that sets the saga back to idle and emits a SAGA_RESET event.
actions:
RESET_TICKET_IMPORT:
intent_type: RESET_TICKET_IMPORT
state: ticket_import
entity_key: import_id
preflight:
rules:
- name: must_be_failed
when:
- path: /_tmp/import_saga/step
op: eq
value: -1
error:
code: NOT_FAILED
message: "ticket import is not in failed state"
core:
rules:
- name: clear_import_state
when: {}
then:
- op: set
path: /status
value: "idle"
- op: set
path: /raw_data
value: ""
events:
- type: TICKET_IMPORT_RESET
payload:
import_id: intent.import_idDurability Guarantees Summary
| What is durable | Mechanism |
|---|---|
| Entity snapshot (saga state) | entity_snapshots table in PostgreSQL |
| Event history | ledger_events append-only table |
| Projection tables | Written by causet-projection-worker from ledger |
| Scheduled events | Enqueued by runtime scheduler service |
The entity snapshot is the source of truth for current saga state. The ledger_events table is the source of truth for all history.