WorkflowsDurable Execution

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:

  1. In-flight intents may fail (their callers receive errors)
  2. Events already committed to the ledger are not lost
  3. The entity snapshot reflects the last successfully processed event
  4. 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.

CapabilityCauset SagasTemporal
State persistenceEntity snapshotWorkflow history
DurabilityEvent-driven, step-levelFunction replay, activity-level
Restart behaviorResume from snapshotReplay full workflow
Activity retriesNot supportedBuilt-in with backoff
External signalsNot supportedBuilt-in
Long sleepsLimited (delay_seconds)Arbitrary duration timers
CompensationNot built-inSaga 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: submit and op: schedule operations 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 Causet

The 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_id

Durability Guarantees Summary

What is durableMechanism
Entity snapshot (saga state)entity_snapshots table in PostgreSQL
Event historyledger_events append-only table
Projection tablesWritten by causet-projection-worker from ledger
Scheduled eventsEnqueued 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.