داده، SQL، قراردادها و ماشین حالت · فصل ۶ — Event، Outbox، Reconciliation و State Machine · 76
Outbox, Durable Intent and Reconciliation
Design one transactional-outbox boundary that records domain change and durable publish intent together, then prove a relay can retry and reconciliation can expose stuck or duplicate work without claiming exactly-once delivery. میتواند «Outbox, Durable Intent و Reconciliation» را برای یک domain محدود مدل کند و constraint، compatibility یا recovery evidence لازم را مشخص کند.
Lesson summary
Design one transactional-outbox boundary that records domain change and durable publish intent together, then prove a relay can retry and reconciliation can expose stuck or duplicate work without claiming exactly-once delivery.
میتواند «Outbox, Durable Intent و Reconciliation» را برای یک domain محدود مدل کند و constraint، compatibility یا recovery evidence لازم را مشخص کند.
This lesson produces
میتواند «Outbox, Durable Intent و Reconciliation» را برای یک domain محدود مدل کند و constraint، compatibility یا recovery evidence لازم را مشخص کند.
Who it is for
Foundation
Worked baseline, explicit evidence table, local fixture and one guided failure probe.
Repair
Reduce to one broken contract/protocol assumption, observe it, repair it, then restore the full case.
Experienced
Compress introductory syntax; require independent compatibility/reliability decision, negative evidence and residual-limit statement.
Prerequisites
This lesson owns one bounded question: how can one service commit its domain change and durable publish intent together, then survive relay retries and expose stuck work without claiming exactly-once delivery? The evidence artifact is Durable Outbox Reconciliation Record v1. It proves only the local boundary and the synthetic observations recorded by the bundled fixture.
1. The owned outcome
You will model one order service that confirms O-1001 and intends to publish OrderConfirmed. The domain mutation, outbox intent, event identity, relay attempt, publish observation, mark state, age, reconciliation decision, and residual consumer risk must remain visible as separate evidence.
2. The dual-write gap
A direct sequence such as commit database -> publish message contains a failure window. If the database commit succeeds and the external publish fails, the domain state says the order is confirmed but there is no durable local record proving that publication still needs to happen. The lab classifies that bounded observation as DUAL_WRITE_GAP_OBSERVED.
3. Durable intent
A transactional outbox moves the publish intent into the same local transaction as the owned domain mutation. In the bounded fixture, OrderConfirmed state and one PENDING outbox row commit together. If the local transaction fails before commit, neither becomes durable. This is the meaning of durable intent in this lesson.
4. Local atomicity is not broker atomicity
The local database transaction does not extend into the external message channel. A successful database commit proves only that the domain change and outbox intent are durable inside the local store. It does not prove that a broker received the event.
5. Outbox event identity
The outbox row uses a stable event_id plus an aggregate_key. Here the event ID is evt-order-O-1001-confirmed and the aggregate key is order:O-1001. These fields support traceability and downstream duplicate handling when their semantics are declared. A UUID by itself does not define ordering or business uniqueness.
6. Relay behavior
The relay reads a PENDING intent, publishes its event, and then marks the row. Those are separate operations. Therefore the relay must be designed for retry rather than assuming one attempt will always finish cleanly.
7. Publish-before-mark crash
The decisive relay failure is a crash after the synthetic external publish but before the local row is marked PUBLISHED. On restart, the row is still PENDING, so the relay publishes the same intent again. The fixture classifies this as DUPLICATE_DELIVERY_CANDIDATE.
8. Why duplicate delivery remains possible
The outbox removes one dual-write gap, but it does not create global exactly-once delivery. A retry can make the same logical event visible more than once. Downstream idempotency is therefore still a separate requirement; DAT-017 supplies that prerequisite boundary rather than being re-taught here.
9. Mark state and retry evidence
For each relay attempt, preserve the attempt number, publish observation, and local mark state. A row that was published once but never marked cannot be treated as safely complete merely because a publish call returned before the crash.
10. Reconciliation
Durable intent creates something that can be inspected later. A reconciliation query can identify outbox rows that are still pending, repeatedly failing, or older than the declared threshold. The lab deliberately leaves one old intent visible and classifies it as STUCK_INTENT_DETECTED.
11. Reconciliation is evidence, not omniscience
A clean reconciliation report means only that the declared local query found no rows matching its criteria. It does not prove every downstream consumer completed its side effect or that no external message was lost outside the modeled boundary.
12. Evidence completeness
The record has ten fields: Intent ID, Aggregate Key, Domain Commit, Outbox Commit, Relay Attempt, Publish Observation, Mark State, Age, Reconciliation Decision, and Residual Consumer Risk. Removing Residual Consumer Risk produces EVIDENCE_INCOMPLETE even when the technical fixture runs.
13. Baseline transactional-outbox probe
baseline_transactional_outbox_commit confirms the order and writes one pending intent in the same local transaction. Expected class: DOMAIN_AND_INTENT_COMMITTED. The self-test also verifies a forced pre-commit failure leaves both domain state and outbox intent unchanged.
14. Direct dual-write failure probe
direct_dual_write_publish_failure intentionally uses the broken direct-publish design. The order state commits, publish fails, and no durable outbox intent exists. Expected class: DUAL_WRITE_GAP_OBSERVED. Preserve this negative evidence after the repair.
15. Relay crash-and-retry probe
relay_publish_before_mark_crash_retry publishes once, crashes before mark, then retries the still-pending intent. The same event_id appears twice in the synthetic delivery log before the row becomes PUBLISHED. Expected class: DUPLICATE_DELIVERY_CANDIDATE.
16. Reconciliation probe
reconciliation_old_pending_intent ages one pending row past the local threshold and records repeated attempts. Reconciliation must surface it without silently marking it successful. Expected class: STUCK_INTENT_DETECTED.
17. Source boundary and freshness
The frozen source boundary has exactly three official sources: Debezium Outbox Event Router, PostgreSQL 18 transactions, and Microsoft Azure Idempotent Consumer. The P8 snapshot was retrieved on 2026-09-02; its next review signal is 2026-10-17, followed by 2026-12-31. On 2026-09-16 no review signal is due, so Query 1 preserves the frozen source boundary without expanding it or inventing a same-locator recheck.
18. Transfer and final bounded decision
Changed context: a billing service cannot share a transaction with its message broker. Design the local durable-intent record, relay retry rule, and reconciliation signal. Your answer must state residual consumer risk and must not promise exactly-once delivery. The local fixture can demonstrate a dual-write gap, local atomic durable intent, a publish-before-mark duplicate candidate, and detection of a stuck intent. It cannot prove broker-wide exactly-once semantics, downstream idempotency, total ordering, or production reliability.
Assessment
There is no answer key in this lesson pack; answer it yourself and mark honestly. "Needs review" sends the lesson to your review queue.
DAT-018-S1 retrieval
State the local durable-intent rule and one non-goal.
DAT-018-S2 application
Run the transactional-outbox baseline and record domain/outbox evidence.
DAT-018-S3 diagnosis
Explain the direct dual-write failure and publish-before-mark retry without claiming exactly-once.
DAT-018-S4 decision
Define the reconciliation threshold/action boundary and residual consumer risk.
DAT-018-S5 transfer
Design durable intent, relay retry, and reconciliation for the billing-service changed context.
Assessment rubric
Critical dimensions: bounded model correctness; evidence quality; scope discipline; transfer independence. Happy-path-only proof or an exactly-once claim is insufficient.
References & freshness
Case studies
Lesson visuals
Lab files
Lesson media & slides
Teaching files (download)