要点: イベント駆動設計は、確定した業務変更に対応するイベントを失わないときに初めて信頼できます。
この記事の用語: Outbox:業務変更と同じトランザクションでイベントを保存するテーブル。Relay:Outboxからブローカーへ送るプロセス。
現場の課題
DB更新とブローカーへの送信は別の操作です。途中でプロセスが止まると、データだけ保存されるか、確定していないデータのイベントが送られます。再試行による重複も避けられません。
ブローカーはサービスを時間的に分離しますが、アプリケーション DBとの原子性は作りません。Outboxで書き込み境界を守り、コンシューマー側では重複、遅延、再実行を前提にします。
設計と実装
- イベントは命令ではなく、すでに起きた事実として過去形で定義します。
- 業務データの変更とOutboxレコードを同じDB トランザクションで保存します。
- イベントは非同期送信し、コンシューマーはイベントIDで重複処理を防ぎます。
実装例
BEGIN
INSERT INTO orders (...) VALUES (...)
INSERT INTO outbox(id, aggregate_id, type, payload)
VALUES (:eventId, :orderId, 'OrderCreated.v1', :payload)
COMMIT
relay.publish_unpublished(limit = 500)本番導入の進め方
リスクの低い副作用を一つ選び、同期経路と並行して結果を比較します。再実行ツール、未送信イベントのダッシュボード、担当者を整えてからコンシューマーを増やします。
まとめ
信頼できるイベント駆動設計では、トランザクション境界、イベント担当者、再試行 Semanticsが明示されています。
