Outbox Events
Use transactional outbox events for reliable SOIT runtime state changes.
SOIT uses a transactional outbox to persist domain facts before dispatching side effects. The outbox keeps runtime state changes and event publication in the same database transaction, so workers can retry dispatch without losing or duplicating committed facts.
Why the outbox exists
Runtime state often changes before asynchronous workers perform follow-up work — indexing a document, executing a workflow node, delivering a notification. If the state change and the event that triggers the follow-up were written separately, a crash between the two would either lose the event or duplicate the side effect. Committing both in one transaction removes that window.
Core tables
| Table | Purpose |
|---|---|
event_outbox | Pending and processed domain events |
event_consumer_checkpoint | Idempotency checkpoint per consumer and event |
dead_letter_events | Failed dispatch records that need operator review or replay |
Event envelope
Each outbox record stores a canonical envelope that is intentionally small and stable:
event_id,event_type,event_version— identify the fact.tenant_id,subject_type,subject_id— scope the affected resource.run_id,task_id,thread_id,workflow_run_id— link back to runtime ledger records.correlation_id,causation_id— preserve causal traceability across event chains.producer,occurred_at,payload— describe the source and data.
Event flow
- A service changes domain or runtime state.
- The same transaction writes an outbox event.
- A dispatcher reads pending outbox events and hands them to workers.
- Workers perform side effects through governed adapters.
- Runtime state is updated with results, failures, costs, and trace evidence.
- Consumers record checkpoints so redelivery is idempotent; undeliverable events land in the dead-letter table for review or replay.
Rules for module authors
Product modules emit facts through the runtime event helpers instead of writing directly to dispatch infrastructure. Events should be versioned, scoped, idempotent where practical, and tied back to tenant, workspace, request, run, and task context whenever they affect execution.
Related pages
- Runtime Ledger — the execution records events link to.
- Data Model — where outbox tables sit in the overall model.