自社プロダクト「カンタン補助金」の基盤移行で、企業情報の新規登録が2日間100%失敗していた。利用者にはエラーとだけ表示されていたが、社内の監視は正常な状態を示し続けていた(出所: 自社の運用記録、確認日2026-09-06)。
この記事で分かること
- 登録だけが100%失敗していたのに、監視がなぜ異常を検知できなかったのか
- 原因になった設定方法の違いは何か
- 実スキーマと突き合わせる検査をどう作ったか
この記事で分からないこと(正直に書く)
- 最初の問い合わせが来るまでの2日間で、実際に何件の登録が失われたか
- 同種の設定方法の違いが、この移行の他の箇所にまだ残っているかどうか
何をしたか: 手書きのSQLへ移植した
データベースの基盤を移行し、既定のORMが生成していた処理を手書きのSQLに置き換えた。その過程で、ある項目に設定していた「未指定なら特定の値を入れる」という既定値の指定が、新しいスキーマの定義に引き継がれなかった(出所: 自社の運用記録、確認日2026-09-06)。
何が起きたか: 読めるが書けない、という非対称
新しいスキーマではその項目が必須(NOT NULL)のまま既定値の指定だけが失われたため、値を渡さない新規登録は必須制約違反で失敗するようになった。企業情報の登録が2日間100%失敗し、利用者にはエラーとだけ表示されていた(出所: 自社の運用記録、確認日2026-09-06)。一方で一覧や詳細の画面はすべての列をそのまま取得して表示するだけなので、影響を受けず200を返し続けていた。
なぜ気づけなかったか: 3重に沈黙する構造だった
監視が異常を検知できなかった理由は3つ重なっていた。1つ目は、一覧・詳細画面がすべての列をそのまま返す処理のため、書き込みだけが壊れていても200を返し続けたこと。2つ目は、例外を握りつぶして応答を返す共通処理があり、実行時エラーの件数が0件のまま推移していたこと。3つ目は、死活監視が稼働確認用のエンドポイントと公開ページしか見ておらず、書き込み処理は監視の対象に入っていなかったことである(出所: 自社の運用記録、確認日2026-09-06)。加えて、失敗していた項目のテーブルは移行前の2ヶ月半、新規作成そのものが発生しておらず、移行直後に誰も試していなかった。最初に試した利用者からの問い合わせで初めて発覚した。
どう直したか: 実スキーマとINSERTの列を突き合わせた
2026年9月、実際に配置されているスキーマ定義を基準にして、必須かつ既定値の指定が無い列を洗い出し、書き込み処理が渡している列の集合と突き合わせる検査を作った。モデル定義だけを見て探す方法では不十分で、実際にモデル側の定義に既定値の指定が無く別の場所で値を明示していた列は、この方法では見つからなかった(出所: 自社の運用記録、確認日2026-09-06)。この検査を通した結果、報告された1件のほかに4件の同型の欠陥が見つかった。共通の作成処理には、新規作成時にだけ既定値を適用する仕組みを持たせ、更新時に既定値で上書きしないようにした。
再発防止: 契約テストで、わざと壊して落ちることを確かめる
実スキーマの必須列をテストの固定値として持たせ、渡せない必須列があればテストが落ちる仕組みにした。作っただけでは検査になっていないため、一度わざと列を欠落させて実際に落ちることを確認した(出所: 自社の運用記録、確認日2026-09-06)。何を検査に書けば次は見つかるかという観点では、モデル定義の読み合わせではなく、実際に配置されているスキーマとの機械的な突き合わせが効いた。
同じ移行を総当たりで実測した経緯は9件が壊れていた話、後工程のビルドが前工程を消した事例は会員画面が13時間消えた話にまとめている。監視の粒度の設計判断は、姉妹記事「監視の粒度を上げるほど費用になる理由」も参考にしてほしい。
自社のデータベース移行や書き込み経路の検査設計について相談したい場合は、お問い合わせから編集部まで連絡してほしい。
よくある質問
Q1. なぜ登録が2日間100%失敗しても監視は正常のままだったのか
一覧・詳細画面が列をそのまま返すため200を返し続けたこと、実行時エラーを握りつぶす共通処理があったこと、死活監視が書き込み処理を対象にしていなかったことの3つが重なっていた。
Q2. 原因になった設定方法の違いとは何か
移行元の既定値の指定方法が、新しいスキーマの定義には引き継がれない性質のものだった。必須制約だけが引き継がれ、値を渡さない登録が制約違反になった。
Q3. どうやって同型の欠陥を見つけたのか
実際に配置されているスキーマの必須列と、書き込み処理が渡している列の集合を機械的に突き合わせた。この方法で、報告された1件のほかに4件の同型が見つかった。
Q4. 再発防止のために何を残したか
実スキーマの必須列を固定値として持つ契約テストを作り、必須列を渡せない場合にテストが落ちることを実際に確認した。