บทที่ 27 · Part 5 — From Model to Running System
Reliable Domain Processes
ดูแล process ข้าม Aggregate/Context ด้วย identity, outbox, idempotency, compensation และ reconciliation
Reliable Domain Processes
Transfer หนึ่งครอบ Intent, Risk, Funds, Provider และ Ledger ไม่มี Aggregate หรือ database transaction เดียวทำทั้งหมดได้ เมื่อ crash เกิดหลัง provider รับคำสั่งแต่ก่อนบันทึกผล คำว่า retry อย่างเดียวอาจ สร้างเงินซ้ำ DDD ต้อง model process identity, intermediate/unknown states, compensation และ repair เป็น business concepts
จบบทนี้คุณจะ
แยก local transaction จาก long-running business process ใช้ stable identity, idempotency, outbox/inbox, Saga/Process Manager, compensation และ reconciliation ตาม failure mode ออกแบบ human decision และ unknown outcome โดยไม่อ้าง exactly-once effect
Business Process มี Lifecycle
candidate TransferProcess/Process Manager ถือ:
Process ID
Intent ID
Policy decisions/versions
Reservation ID
Execution attempts/outcomes
Posting/reconciliation references
Current responsibility / deadline
มัน coordinate commands/facts แต่ไม่ควรเป็น Aggregate ใหญ่ที่แก้ state contexts อื่นโดยตรง
Stable Identity ทุก Boundary
| Boundary | Identity |
|---|---|
| user command | Request/Intent ID |
| funds effect | Reservation/Posting Reference |
| provider request | Idempotency Key + Attempt ID |
| message | Message/Event ID + causation |
| reconciliation | Case/External Record ID |
idempotency ต้องนิยามผลเดิมเมื่อ request ซ้ำและ reject key reuse กับ parameters ต่าง
Outbox/Inbox
Outbox แก้ local dual write: state+outbox ใน transaction เดียว relay ส่งภายหลัง อาจส่งซ้ำ Inbox/dedup ช่วย consumer แต่ business handler ต้อง idempotent
ไม่ได้ให้ exactly-once ทั้ง journey เพราะ external provider/human actions อยู่นอก transaction
Retry ตาม Failure
- validation/domain rejection: ไม่ retry
- known transient unavailable: backoff/jitter/budget
- timeout after side effect possible: reconcile หรือ retry ด้วย same vendor idempotency contract
- permanent decline: business outcome
- unknown schema/contract: quarantine/alert ไม่วน
AWS Making Retries Safe ให้ first-party guidance เรื่อง idempotent API
แต่ละลูกศรข้าม boundary ต้องมี durable identity และ retry contract ส่วน Indeterminate หยุดการสร้าง
side effect ใหม่จน reconciliation ให้ evidence ไม่ใช่ทางอ้อมไป Declined
Timeout ไม่เท่ากับ Failed
Provider อาจรับ request แล้ว response หาย Model INDETERMINATE, หยุด side effect ใหม่ และเปิด
reconciliation ตาม contract ห้ามคืน funds/แจ้ง failed ทันทีโดยไม่มี evidence
Saga, Process Manager และ Compensation
Saga แบ่ง long transaction เป็น local transactions พร้อม compensating actions Process Manager เก็บ state/next action ของ flow Compensation เป็น business action เช่น Release Reservation หรือ Post Correction ไม่ใช่ rollback เวลา
บาง action ชดเชยไม่ได้ เช่น notification ถูกอ่านหรือ FX trade executed ต้อง model forward recovery
Reconciliation เป็น Safety Net
เปรียบเทียบ internal/external facts, classify exceptions, request evidence, apply approved correction, close with audit trail มี backlog owner/SLO อย่าทำเป็น cleanup job ที่แก้ rows เงียบ
Human in the Loop
manual review มี task identity, assignee/role, evidence, decision, expiry/escalation และ policy version event/process ต้องรอได้โดยไม่ lock database
Crash Matrix
| Crash point | Durable evidence | Safe next action |
|---|---|---|
| before outbox commit | none | caller retry same command ID |
| after commit before relay | outbox | relay later |
| after provider effect before response | provider/idempotency unknown | query/reconcile |
| after outcome before posting | execution fact | idempotent posting command |
| after posting before display | ledger fact | rebuild projection |
แบบฝึกปฏิบัติ: Indeterminate Transfer
สร้าง process state machine และ crash matrix อย่างน้อย 8 จุด ระบุ identity, authority, retry class, compensation, reconciliation owner, human step และ customer-visible wording
Acceptance: replay ทุก crash ไม่สร้าง provider effect หรือ ledger posting ซ้ำ และ display cache ไม่ใช้ตัดสิน
รายการตรวจสอบ
- Business process มี identity/lifecycle
- Local vs long transaction แยก
- Idempotency ทุก side-effect boundary
- Outbox consumer ยังรับ duplicate
- Retry ตาม failure class
- Compensation เป็น business action
- Unknown มี reconciliation owner
- Human step durable/auditable
สรุปบทนี้
Process ข้าม contexts ต้อง model uncertainty และ recovery เป็นส่วนของ domain Stable identity, outbox/idempotency, Process Manager, compensation และ reconciliation แก้ failure คนละชนิด ไม่มี pattern เดียวให้ exactly-once business outcome