【懺悔】稼働中の本番DBで殆どのテーブルをtruncateしてしまった話

**これは8年ほど前のある日のことです。**

本番環境のテーブルを淡々とtruncateし続けたことがあります。
リリース前などではなく、稼働中のサービスでした。
思い出せる限り、私のエンジニア歴において最大の「やらかし」です。

「そんなミスありえないだろ…」「どんだけ迂闊なんだよ」という感想を持たれる方もいらっしゃるかと思います。
むしろ、それが正常だと思います。しかし、当時の私はやってしまった。

ただ、それでエンジニアをやめるようなこともなく、現在では人を指導する機会も増えました。

- どうしたらそんな事が起きるのか？
- その後、どのような対応が行われたのか？
- 教訓はなにか？

この機に記させていただきたいと思います。

## 量産現場の社二病社員

当時働いていた職場では、「同じような機能を持ったスマートフォンアプリ」を量産する部署がありました。
私は、そこに配属されました。

当時、新卒２年目。社二病真っ只中だった私は、
「もうCakePHP2は使いこなしてしまったは〜 ^o^」などと調子に乗っておりました。
（もちろん使いこなしてはいません。MVCくらいしか知らないだけです。）

さて、この部署では下記のフローで開発からリリースまで行われていました。

1. アプリの企画書について説明を受け、脳内でフワッとした設計
1. 開発サーバで、既存アプリのソースコードをコピー
1. 開発サーバで、既存アプリのデータベースをdumpしてコピー
1. 本番環境のインフラを、既存のインフラを参考に構築
    1. (本番はAWSを利用していたので、EC2やRDSを作成)
1. 開発環境のDBのdumpを、作成したRDSに適用
1. 開発を進め、都度本番にデプロイ
1. クライアントアプリ開発者は、**本番環境を利用して検証**
1. クライアント、バックエンドの開発が完了したら、ストア申請
1. ストア公開前に、**DBのテーブルをtruncateして初期化**

今となっては色々ツッコミ所のあるフローですが、当時のベンチャー企業では珍しくない基準かと思います。
また、（量産体制であれば整っていた方が良いはずの）手順書なども、無かったか、あっても相当簡易な物だったと思います。
むしろ量産体制だからこそ、とにかく手を動かすような働き方が当然、という空気になっていたと思います。
そんな開発現場でした。

## 違和感発、ボルネオ行き

ともかく、上記のようなフローに則り、いくつかのアプリを開発&リリースしていきました。
最初こそ緊張しながら一つ一つ実行していましたが、すぐ慣れた（ような気になった）ので、
社二病の私ですから、すぐに **「あ〜こんな作業、間違うわけないは〜 ^ν^」** という慢心が生まれていました。

ある日の昼ごろ、慣れたもんだと、何度目かのリリース準備をはじめました。
まったく緊張感なんてありません。
リリース前のDBをいじるのなんて、ストアでアプリが公開されるタイミングに比べれば、なんてことはない。

リリース準備といっても、審査前にデプロイは完了しているので、
DBのテーブルを公開前にクリアしていくだけです。

賢い僕は、テーブルをクリアするためのSQLも用意しています。
**MySQLクライアントにコピペして実行するだけなので安心です**。

目標をセンターに入れてスイッチ！
目標をセンターに入れてスイッチ！
もｋ..

「..あれ？このテーブルがない..」

truncate対象のテーブルがありませんでした。
`SHOW TABLES` しても、たしかにない。

「つーかこんなテーブルあったっけ...？」
「dumpした後で消し忘れてた？」
「このテーブルなかったら、そもそもアプリで動かなくない？」
「ア?」

...ｽｩｯ...
何かの間違いやろ。
とにかくホスト名を確認して、
「ヒヤリハットでしたｗ」と笑い話にさせてくれ...

現実は非情である。
接続していたホスト名を確認すると、**稼働中のサービスのDBでした**。

どうしよう。
どうしよう。
賠償とかになったらどうしよう。
ボルネオ行きの船のチケットはいくらくらいかな。

3秒くらい固まり、そんな事を考えていました。

## ポイント・イン・タイム リカバリ

硬直が解けた後、「ホウ・レン・ソウ!」と思い立ち、ともかく先輩エンジニアに報告と相談をすることにしました。
**「すみません、〇〇アプリのDB、中身ふっ飛ばしちゃいました..。」**
それから、サービスを統括している課長職の方にも報告しました。
怒鳴られるくらいは覚悟していたのですが、「やっちまったねぇ」くらいの内容で、笑顔で対応されたと記憶しています。
きっと怒鳴ったところで仕方ない事は理解されていたのでしょう。
それはそれとしてボルネオ行きの可能性は潰えていないので、全く楽観できません。

そこからは、すぐに下記の対応を行いました。

- 被害を最小限に食い止めるため、サービスをメンテナンスモードに切替
    - アプリケーションへのリクエストを遮断
- データが飛んだ後に登録されたデータがないか確認
- 問い合わせ時の一時的な返答を準備
- 最後にDBのバックアップをとった日付を確認
- 等など...

ふと先輩エンジニアが
「なんかRDSってちょっと前の状態に戻す機能なかった？」
と発言しました。

（そんな凄い機能、あったとしても絶対に使ってないよ…。）
（そもそも設定した覚えもなければ、そんな項目見たこともないし…。）
（お高いんでしょう…？）

みたいな事を考えつつ、期待せずにいろいろ設定内容などを調べてみたら
**ポイントインタイムリカバリ** という項目を見つけました。

先輩とその機能について調べてみると、なんと
「RDSはデフォルトで、ちょっとくらい前の状態まで戻せる...ってコト！？」

**すごい！すごいぞAWS！ありがとう！ありがとう...**

光明が差し込みます。


### 補足

ポイントインタイムリカバリは、RDSインスタンスのある時点の状態を、別のRDSインスタンスで再現する機能です。
つまり、新規にRDSインスタンスを開始し、トランザクションログから、指定した日時の状態に復旧する形式です。
RDSインスタンスは、既存のものとは別に作成することになるので、
RDSインスタンスへの各種設定の他、アプリケーションの設定変更(DB接続先変更等)が必要です。
よって、復旧までにはそれなりに時間を要します。
（少なくとも1時間以上は掛かったと記憶しています）

## 復旧

その日のうちに復旧が完了し、メンテナンスモードの解除と、ユーザーへのお知らせを行いました。
問い合わせなどが大量に来るのでは、と思いましたが、思いの外ユーザーからの反応は少なかったと記憶しています。
すぐにメンテナンス状態に入れたのが幸いしたのだと思います。
それでも、「とんでもないことをやってしまったなあ」という気持ちはしばらく消えませんでしたし、
その日の夜はあまり寝ることができませんでした。

## 学び


### 最悪を想定し、対策を行う

まず、自分ほどではないかもしれないけど、人はとんでもない失敗をしてしまうのだという事を学びました。
それは、結局慢心からだったりします。
自分の行為で齎される、**一番最悪な結果というのを想像すべき**です。

今回の失敗では、最悪な結果は、他のアプリケーションのデータをクリアしてしまうことでしたが、
**最悪が現実になった場合、どう復旧できるかを知っておく** のも大事だと思います。
**失敗を過度に恐れてしまっても、生産性が下がります**。

### 自分は信用できないし、人は失敗する

流石に長い鼻も根本から折れたわけですが、
このまま大きなミスをせずにエンジニアを続けていたら、
さら自惚れに拍車がかかっていたのだろうかと思うと、それも恐ろしい。
まだ２年目だったことはむしろ幸いだったのかもしれません。

エンジニアは皆、自分よりはしっかりしている...という風に感じます。
それでも、自分ほどではないけど、
**人はやはりミスをするので、その可能性を減らすための施策を行うべき**です。
今回の失敗は、ダブルチェックや作業手順書といった施策で防止できたと思います。
作業に慣れてしまうと冗長に感じる事もありますが、断じて無駄ではありません。
ダブルチェックは教育的な観点でも有効ですし、残った手順書は財産になります。
ただ、作業者が自ら進んで、これらの施策に時間をかけるのが難しい事もあると思います。
組織的に推奨し、なんだったら強制するくらいで丁度良いと思います。


### すぐ相談できる関係を持つ

酷い失敗をしたものの、**すぐに相談したのは正解だった**と思います。
初動が早かったのは、問い合わせが少なかった要因の一つだったのではないかと。
問題が起きたらすぐ相談。これは当然の事ではあるものの、
リモートワークが普及して同僚・上司とのコミュニケーションが少なくなったり、
働き方も多様になり「ナンノブマイビジネス」的な働き方も増えたのではないかと思います。
結果、すぐに相談できる人がすぐに思い浮かばない...となれば、初動が遅れます。

すぐに相談できる関係を同僚や上司と構築することも大事ですし、
逆にリーダーや上司といった立場なら、部下がすぐに相談できるような「人格」を持つべきだと思います。

### やっぱりクラウドっていいよね

もうRDS以外を利用する気にはなれません。
いや、他のクラウドベンダーも似たような事はできるのだろうとは思いますが、
少なくとも、自分でDBサーバを構築する気持ちは全く無くなりました。
もちろん、EC2やオンプレでも、binlogさえ保持しておけば、似たような対策が取れるのでしょう。
でも、こういった設定は、スピードを重視する現場だと省略されがちだと思います。
最近はAuroraもserverless v2なんかも出て、どんどんデベロッパの管理すべき領域が減っています。
それで良いのだと思います。
クラウドベンダー以上の環境なんてそう簡単には作成できません。

## 最後に

まずは、
当時サービスに関っていたチームの皆さん、
ご迷惑をおかけしたユーザーの皆様、
誠に申し訳ございませんでした。

実は、当時ポイントインタイムリカバリに導いてくれた先輩エンジニアに誘われて、今の会社で働いています。
今では上司と部下の関係です。
(あの時あれ程お世話になったのに、一丁前にこちらからイジったりして、とにかく楽しく働かせてもらっています)

弊社ではエンジニアを始めて間もないメンバーも多いのですが、
緊張しすぎているメンバーにも、緊張が足りないと感じるメンバーにもこの話をしています。
緊張しすぎているメンバーには、「最悪ポイントインタイムリカバリがある」と伝え、
緊張が足りないと感じたメンバーには「**俺はそんな感じでtruncate職人になったよ**」と伝えています。

**この記事は[Qiita Engineer Festa 2022 「私が体験した1番ゾッとするインシデントの話」]( https://qiita.com/official-campaigns/engineer-festa/2022)キャンペーンに参加しています。*