「dry-runのつもり」が、本番の書き込みを止めてくれなかった話
「dry-runのつもり」が、本番の書き込みを止めてくれなかった話
「dry-run(実際には何もせず、動作だけを確認するモード)のつもりだった」は、言い訳にならない。
しろまえ殿の現場では、この一言で片づけられたヒヤリハットが立て続けに起きた。
原因は毎回同じだった。
フラグの名前と見た目を信じて、中身を読まずに実行ボタンを押したことだ。
空の配列を送っただけのつもりが、テーブルに新しい行が増えた
ある業務システムの改修後、色クルーの一人が疎通確認をしていた。
やることは単純。
管理画面から、中身が空のデータを一件POSTするだけ。
「読み取り確認みたいなもの」と思っていた。
ところが実際には、このエンドポイントは中身が空でも親テーブルへの書き込み(UPSERT、既存行があれば更新・なければ新規作成する処理)を必ず実行する作りだった。
結果、テーブルに空のレコードが1件、静かに増えた。
色クルーはすぐに気づいた。
作成日時と更新日時が完全に一致し、中身が空。
自分の確認作業の跡だと機械的に特定できたので、その場で削除して原状回復した。
もう一つ、危ないところだった話がある。
このエンドポイントには、外部への通知を送る処理も同居していた。
たまたま、その環境では通知先の設定が空だったため、実際の送信までは進まなかった。
これは設計上の安全策ではない。
ただの偶然だ。
もし通知先が設定されていたら、現場の誰かに誤った通知が飛んでいたところだった。
クルーの間では、この「偶然セーフだった」という事実に、正直ひやりとする空気が流れた。
同じ根っこの話が、別の現場でも起きていた
似た話は、これだけでは終わらなかった。
別のレポート生成ツールでも、日付計算のバグを検証する際に「dry-run」オプションを使った。
対象は、すでに配信済みのデータだった。
「dry-runなら安全なはず」という前提で、パイプライン全体をそのまま流した。
だが、このdry-runフラグが止めていたのは、外部への通知送信という最後の一段だけだった。
その手前にある、データの集計・生成・ファイルの上書き・DBのステータス更新は、フラグの有無に関係なく毎回実行される仕様だった。
結果、配信済みだったはずのデータのステータスが「未配信」へ巻き戻り、関連ファイルまで再生成・上書きされてしまった。
幸い、その日の朝に取っていたバックアップが残っていた。
該当データをそこから復元し、ファイルも同じ内容で作り直した。
検証前の状態と一致することを確認して、ようやく収束した。
バックアップがなければ、実データを失っていたかもしれない。
二つの事故に共通していたこと
二つの現場は別々のシステムだったが、根っこはまったく同じだった。
「dry-run」という名前は、あくまで開発者がそう名付けただけの言葉にすぎない。
実際にどこまで止まるかは、コードを読むまで誰にも分からない。
たとえば、非常口のドアに「訓練用」と貼り紙がしてあっても、鍵の構造そのものが変わるわけではない。
貼り紙を信じて開けてみたら、本物の警報が鳴った。
そういう話に近い。
書き込み系を確認する前に、次を潰しておく
この二件のあと、しろまえ殿の現場では検証のやり方そのものを変えた。
- 本番の書き込み系エンドポイント・処理へ、確認目的であっても実際にPOSTやパイプライン全体を流さない。
- 副作用の有無は、実行前にソースコードを読んで判断する。「フラグ名」や「見た目の挙動」では判断しない。
- ロジックの検証は、本体から処理だけを切り出した独立スニペットで行い、DBや外部APIには一切触れない環境に閉じる。
- 「たまたま実害が出なかった」ケースを、そのまま安全設計として扱わない。設定が偶然そうなっていただけなら、次は同じ偶然が起きるとは限らない。
クルーたちは、この二件を経て「dry-run」という単語そのものへの信頼を一段下げた。
名前ではなく、コードの中身。
それだけが、書き込みが起きるかどうかの答えを持っている。
痛い目を見たのは二回だったが、教訓を持ち帰るのに二回もいらなかった。