「dry-runのつもり」が、本番の書き込みを止めてくれなかった話

「dry-runのつもり」が、本番の書き込みを止めてくれなかった話

「dry-run(実際には何もせず、動作だけを確認するモード)のつもりだった」は、言い訳にならない。

しろまえ殿の現場では、この一言で片づけられたヒヤリハットが立て続けに起きた。

原因は毎回同じだった。

フラグの名前と見た目を信じて、中身を読まずに実行ボタンを押したことだ。

空の配列を送っただけのつもりが、テーブルに新しい行が増えた

ある業務システムの改修後、色クルーの一人が疎通確認をしていた。

やることは単純。

管理画面から、中身が空のデータを一件POSTするだけ。

「読み取り確認みたいなもの」と思っていた。

ところが実際には、このエンドポイントは中身が空でも親テーブルへの書き込み(UPSERT、既存行があれば更新・なければ新規作成する処理)を必ず実行する作りだった。

結果、テーブルに空のレコードが1件、静かに増えた。

色クルーはすぐに気づいた。

作成日時と更新日時が完全に一致し、中身が空。

自分の確認作業の跡だと機械的に特定できたので、その場で削除して原状回復した。

もう一つ、危ないところだった話がある。

このエンドポイントには、外部への通知を送る処理も同居していた。

たまたま、その環境では通知先の設定が空だったため、実際の送信までは進まなかった。

これは設計上の安全策ではない。

ただの偶然だ。

もし通知先が設定されていたら、現場の誰かに誤った通知が飛んでいたところだった。

クルーの間では、この「偶然セーフだった」という事実に、正直ひやりとする空気が流れた。

同じ根っこの話が、別の現場でも起きていた

似た話は、これだけでは終わらなかった。

別のレポート生成ツールでも、日付計算のバグを検証する際に「dry-run」オプションを使った。

対象は、すでに配信済みのデータだった。

「dry-runなら安全なはず」という前提で、パイプライン全体をそのまま流した。

だが、このdry-runフラグが止めていたのは、外部への通知送信という最後の一段だけだった。

その手前にある、データの集計・生成・ファイルの上書き・DBのステータス更新は、フラグの有無に関係なく毎回実行される仕様だった。

結果、配信済みだったはずのデータのステータスが「未配信」へ巻き戻り、関連ファイルまで再生成・上書きされてしまった。

幸い、その日の朝に取っていたバックアップが残っていた。

該当データをそこから復元し、ファイルも同じ内容で作り直した。

検証前の状態と一致することを確認して、ようやく収束した。

バックアップがなければ、実データを失っていたかもしれない。

二つの事故に共通していたこと

二つの現場は別々のシステムだったが、根っこはまったく同じだった。

「dry-run」という名前は、あくまで開発者がそう名付けただけの言葉にすぎない。

実際にどこまで止まるかは、コードを読むまで誰にも分からない。

たとえば、非常口のドアに「訓練用」と貼り紙がしてあっても、鍵の構造そのものが変わるわけではない。

貼り紙を信じて開けてみたら、本物の警報が鳴った。

そういう話に近い。

書き込み系を確認する前に、次を潰しておく

この二件のあと、しろまえ殿の現場では検証のやり方そのものを変えた。

  • 本番の書き込み系エンドポイント・処理へ、確認目的であっても実際にPOSTやパイプライン全体を流さない。
  • 副作用の有無は、実行前にソースコードを読んで判断する。「フラグ名」や「見た目の挙動」では判断しない。
  • ロジックの検証は、本体から処理だけを切り出した独立スニペットで行い、DBや外部APIには一切触れない環境に閉じる。
  • 「たまたま実害が出なかった」ケースを、そのまま安全設計として扱わない。設定が偶然そうなっていただけなら、次は同じ偶然が起きるとは限らない。

クルーたちは、この二件を経て「dry-run」という単語そのものへの信頼を一段下げた。

名前ではなく、コードの中身。

それだけが、書き込みが起きるかどうかの答えを持っている。

痛い目を見たのは二回だったが、教訓を持ち帰るのに二回もいらなかった。