通知を二重に送らない — 冪等性と運用の仕組み

同じメールを2回送らない、送り漏れにも気づける。通知基盤の信頼性設計

冪等性重複送信防止Cron死活監視エラー通知
読了時間: 9分

はじめに

予約確認メールが2通届いたら、お客様は「予約が二重になったのでは」と不安になります。逆に1通も届かなければ、予約できたのか分かりません。

この記事では、通知を過不足なく届けるための仕組みを紹介します。地味な話ですが、ここが崩れると信頼を失うのは一瞬です。

送信履歴を持たずに重複を防ぐ

メール送信の記録を残さない選択

「送信済みメールの一覧テーブルを作り、送る前に確認する」という方法が一般的です。しかし今回は、あえてその仕組みを持ちませんでした。

代わりに、メールを送る前段階の処理そのものを1回しか実行させないようにしています。処理が1回しか走らなければ、メールも1通しか出ません。

重複防止のアプローチ
BEFORE
送信履歴で確認する

履歴の記録に失敗すると重複する。宛先の記録が個人情報の保管場所になる

AFTER
処理自体を1回に限定する

メールは処理の副産物。処理が1回なら、確認しなくても1通しか出ない

副次的な効果として、メールアドレスを記録する場所が1つ減りました。個人情報は持たないに越したことはありません。

条件付き更新で早い者勝ちにする

予約確定の処理は、決済サービスからの通知と、お客様が完了ページを開いたタイミングの両方から呼ばれる可能性があります。

そこで処理の入り口で、「まだ確定していない状態のときだけ確定にする」という条件付きのデータベース更新を行います。更新できた側だけが処理を続け、メールを送ります。更新できなかった側は何もせず終了します。

同じ警告を繰り返さない

予約管理システムとの同期に失敗したとき、運営者に警告メールを送ります。ただし1時間ごとの定期処理が同じ失敗を検出し続けると、同じ警告が毎時間届いてしまいます。

そこで警告を送るときの更新にも条件を付けました。「まだエラー状態でない場合のみ、エラー状態にする」という形です。すでにエラー状態なら更新は行われず、メールも送られません。

同様に、決済済み予約のキャンセル検出でも、対応済みの目印を付けることで再通知を防いでいます。

定期処理の落とし穴

「今日の分」で探すと取りこぼす

自動課金の対象を探すとき、「課金予定日が今日と一致する予約」で検索すると危険です。定期処理が何らかの理由で1日動かなかった場合、その日の分が永久に取り残されます

そこで「課金予定日が今日以前で、まだ課金していない予約」で検索するようにしました。1日止まっても、翌日にまとめて処理されます。

定期処理の設計原則
範囲で探す

「今日」ではなく「今日以前」。1回飛んでも次で拾える

件数に上限を設ける

1回の実行で処理する件数を制限し、時間切れを防ぐ

必ず正常終了を返す

エラーで途中終了せず、個別の失敗は記録して次へ進む

実行の入り口を守る

定期処理はURLへのアクセスで起動する仕組みのため、URLを知られると誰でも実行できてしまいます。そこで合言葉による認証をかけました。

重要なのは、合言葉が設定されていない場合は実行を拒否することです。「設定を忘れたら誰でも実行できる」という作りは事故のもとです。設定がなければ動かない方向に倒しておきます。

「何も起きていない」を報告する

ゼロ件でも送るメール

自動課金の日次レポートは、対象が0件でも必ず送信します。一見無駄ですが、これには明確な目的があります。

毎日「本日の対象は0件でした」というメールが届いていれば、それが途絶えたときに異変に気づけます。メールそのものが生存確認になっているわけです。

逆に、送らないメール

一方で、10分ごとに動く仮押さえの解放処理は、メールを一切送りません。「0件解放しました」が1日144通も届いたら、本当に重要な通知が埋もれてしまいます。

1時間ごとの同期確認も、変化を検出したときだけ送ります。

頻度が高いほど通知は絞る。この使い分けが、通知疲れを防ぐ鍵です。

メールの失敗で業務を止めない

送信失敗はビジネス処理を巻き戻さない

決済は成功したのに、メール送信でエラーが起きたらどうすべきでしょうか。決済を取り消すべきではありません。

そこでメール送信は、すべて「失敗しても処理全体は続行する」形で実行しています。複数のメールをまとめて送るときも、1通の失敗が他の送信を止めないようにしました。

お金が動く処理と、通知の処理を切り離す。メールは大事ですが、それ自体が業務の本体ではありません。

開発環境では送らない

メール配信サービスの設定がない環境では、送信を試みず記録だけ残して先へ進みます。開発中に本物のメールが飛ぶことも、設定がないせいで機能が動かないこともありません。

ログに何を残すか

メールの送信に失敗したとき、ログに残すのは予約番号とエラーの種類だけです。宛先のメールアドレス、メールの本文、配信サービスからの応答内容は残しません。

ログは調査のために残すものですが、同時に情報漏洩の経路にもなり得ます。「調査に必要な最小限」を意識して選んでいます。

まとめ

通知基盤の信頼性設計で押さえたのは、次の3点です。

  1. 処理を1回に限定して重複を防ぐ — 送信履歴に頼らず、条件付き更新で早い者勝ちにする
  2. 「何も起きていない」を報告する — 日次処理はゼロ件でも送り、途絶えたときに気づけるようにする
  3. メールの失敗で業務を止めない — 決済や予約の処理と、通知の処理を切り離す