背筋が凍りついた話
夏なので怖い話をします。
アプリのユーザ体験イベント直前に、DBのコンテンツ管理テーブルを吹き飛ばしたことがあります。
経緯
デモ環境DBのダッシュボード(GUIでデータ表示&操作ができる)で、不正なデータを消す作業をしていた時のことです。
本来この手の作業はプログラムを書いて自動でやらせるのが筋なのですが、
消したいデータの数が少なくもなく多くもなく、だったため、手作業でやってしまうことにしたのでした。
ダッシュボードからデータを消すときには、
- 消したい行のチェックボックスをチェックする
- ダッシュボードのメニューを開き、「選んだ行を削除」を選択する
という操作をすることになります。
しかし面倒なことに、ダッシュボードには
- 複数行まとめてチェックすることができない
- ある程度以上の数の行をチェックしている場合、削除前に確認作業(テーブル名の入力)を要求される
という仕様があり、大量のデータを消すのはそれなりに手間がかかります。
そんな時に目に入ったのが
クエリで削除対象をフィルタ → Delete all rows → 大勝利
全身が凍りついたのはその直後でした。
何をしてしまったのか
"Delete all rows"は
、内部的には"purge"
という操作を行います。
"purge"
とはつまり、「指定したテーブルの全データの削除」です。
消し飛んだのは、アプリの写真コンテンツを管理するテーブルでした。
これが無くなることは、アプリから写真コンテンツが消え去ることを意味します。
ユーザ体験イベントを前にして・・・
不幸中の幸い
挽回の足がかりはそれでも残っていました。
テーブルデータには日次バックアップがあった
DBはmLabを使っていたのですが、日次でフルバックアップを取る設定をしてありました。
やらかしたのがデモ用環境で、通常アクセスがほとんど無かったと言うことも幸いし(全く無かったわけではない; oplogも多少使った)、
比較的容易に復旧ができました。
写真のファイルデータ自体は消えていなかった
写真のファイルデータはS3上にあり、写真テーブルはS3上のファイルへのリンクのみを保持していました。
写真テーブルには、データの削除後にリンク先ファイルの削除も行うようフックをかけていたのですが、purge
はフックを無視するという仕様のため、ファイルの削除が走っていませんでした。
今思い返しても、これは運が良かったとしか言いようがありません。
このような首の皮一枚の幸運も手伝い、上司・同僚の協力も得て、すみやかに後遺症なく復旧することができたのでした。
教訓
本件の教訓は、ダッシュボードでデータ操作をしないことにつきると思います。
我々が使用していたダッシュボードはDBの管理者権限を与えられているため、ほぼ全ての操作が可能です。
そのようなものが(ダッシュボードがGUIであるために)集中力が低下した状態でも使えてしまうと、フールプルーフがあってもそれを無視して破壊的な誤操作をやってしまう、という事態を招きかねず、
また実際にそのような事態になったわけです。
とはいえダッシュボードを完全に捨てるわけにも行かないので、現実的な対応として、
ダッシュボードはデータの確認のみに使い、データの操作はプログラム的に行うことにしました。
この場合、作業の流れは
- 対象データをダウンロード
- 対象データを(REST APIで)操作
となるので、操作前に対象データの一覧を確認するのが簡単です。