--- title: "「全部別件」ではなかった――AIと追った早朝5時の障害対応" description: "ある朝、5秒のあいだに6件の障害通知が届きました。その日は新しいバージョンを配る予定だったので「たぶん配布が悪さをした」と見当はついていました。当たってはいたものの、そこから先が想像の外でした。読み上げが機械音声に落ち、YouTube通知が止まり、新バージョンが自動で巻き戻され、しかもその巻き戻しの判定基準自体が消えていた。別々に見えた症状が、一度の更新作業から枝分かれしていたと分かるまでを、AIと一緒に追った記録です。" url: https://ryuuneko.com/blog/ai-in-incident-response published: 2026-09-13 22:40:52.774656 updated: 2026-09-13 22:40:52.774656 --- 朝の 5 時に、Discord に障害通知が届きました。5 秒のあいだに 6 件。 その日は、毎朝やっている自動の更新作業に加えて、新しいバージョンを配る予定が入っていました。だから、見当はついていました。**たぶん、その配布が何か悪さをしている。** そう思って、確認に入りました。 見当は当たっていました。ただし、当たっていたのは「配布が悪さをした」というところまでで、**何がどう壊れて、どこまで波及していたか**は、そこからまったく想像がつかない形をしていました。 この記事は、その朝に起きたことを順番に書いたものです。技術の解説より、「一人で見ていたら、たぶんどこかで見落としていた」という話が中心になります。 念のため書いておくと、調べたのは一人ではありません。**サーバーのログ、設定ファイル、監視の記録、手元のソースコードとその変更履歴を、まとめて読める状態にしたAIと一緒に追いました。** 以下で「見にいった」「確かめた」と書いているのは、だいたいその二人がかりの作業です。 --- ## 最初に見えたのは、たった一行 サーバーの中で動いているものを一覧で出すと、ほとんどが「正常」と表示されていました。3 か月連続で動いているもの、11 日動いているもの。ディスクの空きも余裕。公開しているサイトも普通に開きます。 その中で、一つだけ違う表示がありました。 ``` voicevox-proxy Up 2 minutes (unhealthy) ``` 音声合成につなぐ中継役が、起動はしているのに「不健全」と自分で名乗っている。 同じ時刻の読み上げボットのログを見ると、こうなっていました。 ``` voicevox synthesis failed, trying espeak-ng fallback espeak-ng fallback succeeded ``` 音声合成に失敗して、代わりの簡易な音声で喋っている。つまり利用者には、いつものキャラクターの声ではなく、味気ない機械音声が聞こえていたことになります。エラー画面が出るわけでもなく、無言になるわけでもない。**代わりのもので、静かに動き続けていた。** この「静かに劣化する」という壊れ方は、自分で仕込んだものです。音声が作れなかったときに黙り込むより、聞こえにくくても喋ったほうがマシだろうと思って、代替手段を用意してありました。設計としては正しかったと今でも思います。ただ、正しい代替手段は、**壊れていることを隠します。** --- ## 「つながっていない」のか「つながっているのに動かない」のか 中継役は「音声合成の本体が 2 台とも死んでいる」と主張していました。 ``` health: 0/2 alive ``` ところが、その 2 台のコンテナは普通に起動していて、ログを見ると他所からの問い合わせには正常に答えています。 ここが最初の分かれ道でした。「本体が死んでいる」のか「中継役が死んでいると思い込んでいる」のかで、やることが正反対になります。 やったのは単純な確認です。**中継役の中から、本体に 10 回続けて問い合わせる。** ``` byname ok=10 ng=0 byip ok=10 ng=0 ``` 名前で 10 回、IP で 10 回、全部成功。つまり通信経路はまったく健全で、中継役だけが「死んでいる」と言い張っている。 この時点で、ネットワークを疑う道が消えました。これは地味ですが大きくて、こういう症状は普通「ネットワークが不安定なのでは」「たまたま落ちたのでは」という方向に時間を溶かします。10 回試して 10 回成功した事実があると、その道に入らずに済みます。 一度、中継役を再起動してみました。同じでした。一時的な不調ではない。 --- ## 10 日古いだけのプログラム 残った可能性は「中継役のプログラムそのものがおかしい」です。 そこで、動いているプログラムがいつ作られたものかを確認しました。**6 月 10 日**のものでした。手元には 8 月 27 日に作った新しいものがあります。 なぜ古いほうが動いていたか。ここは少し設計の話になります。 このサーバーでは、どのプログラムを動かすかを設定ファイルに書いています。その設定で、中継役だけ「どれを使うか」を書き忘れていました。名前を指定しないと、いちばん新しいという意味の名札が付いたものが選ばれます。ところがこの中継役は、他と違って手作業で入れ替える運用だったので、**その名札が 6 月のものに付いたまま残っていた。** つまり「最新」という名札の付いた、3 か月前のプログラムが動いていたわけです。 そして決定的だったのは、6 月 20 日の変更内容でした。この日、接続先の書き方を変えています。 ``` CPU-1|http://<合成サーバーのアドレス> ``` 前半がラベルで、後半がアドレス。この書き方に対応したのが 6 月 20 日で、動いていたプログラムは 6 月 10 日。**10 日足りない。** 新しい書き方を知らないプログラムは、この文字列をまるごとアドレスとして扱おうとして、当然どこにもつながらず、全部だめだと判定していました。 設定ファイル側は新しく、プログラム側が古い。片方だけ進んでいたわけです。 新しいほうに名札を付け替えて入れ直したら、こうなりました。 ``` health: 2/2 alive ``` 読み上げボットのログにも一行出ました。 ``` VOICEVOX is BACK online ``` --- ## ついでに見つかった、もう一つ 直った勢いでログを眺めていたら、5 秒おきに同じ警告が流れているのに気づきました。 ``` youtube WS error, reconnecting in 5s error=HTTP error: 401 Unauthorized ``` YouTube の新着通知を受け取る接続が、認証に失敗し続けている。401 は「あなたが誰か分からない」という意味です。 調べると、**ボット側に認証用の合言葉が一つも入っていませんでした。** 受け取る側には 64 文字の正しい値が入っている。設定ファイルにも同じ値がある。ただ、それをボットに渡す記述だけが無かった。 以前は手作業でその場で渡していて、それで動いていたようです。手作業で渡した設定は、**コンテナを作り直すと消えます。** 今朝、作り直しが走った。それで消えた。 実はこれとまったく同じ型の事故を、以前も起こしています。別の設定を手作業だけで渡していて、作り直しで消えて、全部止まったことがありました。そのとき「設定ファイルに恒久的に書く」と決めたはずなのに、別の設定で同じことをやっていたわけです。 今回は設定ファイルに書き足して、なぜそうするのかをコメントで残しました。書き足したあと、接続はすぐ通りました。 ``` youtube WS connected youtube WS subscribed count=2 ``` --- ## ここまでが前半で、本題は後半でした ここまでで「不具合 2 件を直した」つもりでいました。実際、利用者から見える範囲はもう正常です。朝に届いた 6 件の通知も、これで説明がつく。そう思っていました。 その後、念のため監視の記録を最初から読み直しました。ここで、話が引っくり返ります。 朝の通知は、こう並んでいました。 ``` 04:58:06 VOICEVOX (proxy) DOWN 04:58:07 Web Server DOWN 04:58:08 BOT #1 DOWN 04:58:09 BOT #2 DOWN 04:58:09 API DOWN 04:58:10 Scheduler DOWN ``` ここまでは知っています。これを見て確認に入ったわけですから。問題は、**その続きに知らない行があった**ことです。 ``` [zunda v3.2.1 配布] 異常を検知したので旧版に戻します: 起動後 2 分で健全にならない ``` **その日の朝に予定していた新バージョンの配布が、自動で巻き戻されていました。** しかも、私が調べているまさにその最中に。 配布の記録をさかのぼると、原因が一本につながりました。 1. 朝の配布作業が、まず中継役を立ち上げる 2. その中継役が、さっきの「10 日古い」問題で不健全になる 3. 読み上げボットは「中継役が健全になるまで待つ」という設定になっていて、**起動できない** 4. 配布を見張っている仕組みが「2 分たっても健全にならない」と判断し、**前のバージョンに戻す** つまり、朝いちばんに見つけた「読み上げが機械音声」も、「YouTube が 401」も、「新バージョンが消えた」も、**全部、同じ一度の更新作業をきっかけに枝分かれしていた症状**でした。バラバラの 3 件だと思っていたものが、一本の流れでつながった。 ![毎朝の更新作業を起点に、中継役が古いプログラムで起動したことと手で入れた設定が消えたことの2つが生まれ、そこから読み上げの代替音声・YouTube通知の失敗・新バージョンの巻き戻しという3つの症状に枝分かれしていく図](/blog/uploads/ai-in-incident-response-chain.svg) --- ## 巻き戻しの判定が、そもそも壊れていた ここでもう一段あります。 巻き戻しの判断に使っていたのは、ボットが自分の状態を答える窓口です。そこに問い合わせて返事が無いから「健全でない」と判定した。 その窓口を確認したら、**外から届かない状態でした。** 設定上、外に出す記述が消えていた。 消えたタイミングも分かります。さっきの 6 件の通知です。ボット、2 台目のボット、API、スケジューラが 4 時 58 分に揃って「DOWN」になっている。**それまでは応答していた**ということです。つまり朝の配布作業が、中継役を古いプログラムで立ち上げたのと同時に、この窓口の設定も消していた。 これが何を意味するか。**巻き戻し先の古いバージョンでも、同じように返事はしません。** 判定基準のほうが消えているので、何を配布しても「健全にならない」と言われて巻き戻る。新バージョン自体は、おそらく最初から正常でした。 実際、巻き戻しの 1 分後には、こういう通知も届いていました。 ``` 旧版への復旧でも健全になりません。手動対応が必要です ``` 戻しても直らない、と仕組み自身が正しく報告していたわけです。判定基準が壊れているのだから当然です。 そしてこの「外に出す記述」も、以前に手作業で直したものでした。そのときの記録にはこう書いてあります。「設定ファイルを標準のもので上書きすると、また消える」。予言どおりに消えていました。 窓口を出し直したら、4 つとも即座に応答するようになり、監視も追いつきました。 ``` 18/18 healthy ``` そのうえで、新バージョンを配布し直しました。今度は中継役が健全なので、何事もなく起動します。 --- ## 通知は仕事をした。それでも足りなかったもの 今回、監視の仕組みは満点に近い働きをしています。 障害の開始を 5 秒で 6 件まとめて知らせ、直したら復旧したと知らせ、巻き戻したと知らせ、そのうえで「戻しても健全になりません。手動対応が必要です」まで送ってきました。受け取った側も、見当をつけて数分で確認に入っています。通知が来なかったわけでも、無視したわけでもありません。 それでも、朝の時点で分かっていたのは**「配布のあたりで何かが壊れた」までです。** 通知に書けることには限りがあります。「止まりました」は書ける。「直りました」も書ける。でも、 - 中継役が 3 か月前のプログラムで起動していること - そのせいでボットが依存関係の待ちから抜けられないこと - 数分後に、その状態を見た仕組みが新バージョンを巻き戻すこと - 巻き戻しの判定に使う窓口が、同じ原因で消えていること このあたりは、どれも通知には現れません。**現れないどころか、4 番目はまだ起きてすらいませんでした。** 巻き戻しが走ったのは、私たちが調べ始めてから 15 分後です。 ![その朝の通知を時間軸に並べた図。4時58分に5秒間で6件の停止通知が届き、それを受けて調査が始まったこと、新バージョンの巻き戻しはその15分後に起きたことを示している](/blog/uploads/ai-in-incident-response-alerts.svg) 一つだけ、通知の出し方で直せる余地はあります。**毎朝の更新作業でも、コンテナを止め直すので「DOWN」は必ず出ます。** つまり正常な作業と本物の異常が、同じ見た目で同じ時間帯に届く。今回は「配布の日だ」と知っていたから見当がついただけで、知らなければ模様に紛れていたはずです。作業が終わったあとも戻っていないものだけを改めて知らせる、といった区別はつけられます。 ただ、本筋はそこではありませんでした。**通知は「何かが起きた」を伝える。「なぜ」と「この先どうなるか」は伝えない。** そこを埋めるのが調査で、今回時間がかかったのも、危なかったのも、全部そちら側です。 ## で、AIが居ると何が楽だったか ここからが本題です。 **楽なのは「速い」ことではありませんでした。** 一番効いたのは、**同時に何か所も見られる**ことです。今朝の作業でいうと、自宅サーバーの状態、外側のサーバーの状態、公開サイトの応答、中継役のログ、ボットのログ、監視の記録、設定ファイル、そして手元のソースコードの変更履歴。これを行ったり来たりしながら、矛盾する 2 つの事実を突き合わせる作業でした。 「中継役は 0/2 だと言っている」と「同じ場所から 10 回問い合わせて 10 回成功する」は矛盾します。この矛盾に気づけるかどうかが分かれ目で、気づくには両方を同時に見ている必要がある。片方ずつ見ていると、どちらか片方を信じてしまいます。 次に効いたのが、**決め打ちをしないこと**です。 私は最初「一時的に落ちただけだろう、再起動で直る」と思っていました。実際に再起動もしました。直りませんでした。人間だけだと、ここで「もう一回再起動」「様子を見る」に流れやすい。今回は、再起動で直らなかった時点で「じゃあプログラム自体が違うのでは」と、素直に次の可能性に移れました。 三つ目は地味ですが、**過去の自分の記録を引っ張り出せる**ことです。「手作業で渡した設定は作り直しで消える」という教訓も、「設定ファイルを上書きすると窓口の記述が消える」という予言も、どちらも前に自分で書き残したものでした。書いたことを覚えていなくても、引っ張り出せれば効きます。**今回の 2 つの原因は、どちらも過去の自分がすでに警告していたものでした。** --- ## かき乱されたところも書いておく いいことばかり書くと嘘になるので、引っかき回された場面も並べます。 **一つ目。捨てろと言ったら、本当に捨てる。** 別件で、作りかけのまま放置されていた変更が 400 行ほどありました。どうするか聞かれて「取り下げる」と答えました。実際それは正しい判断でした。 ただ、その作りかけの中に、**まったく別の調査結果が混ざっていました。** 何をどう測って、何がどれだけずれていたかという実測の記録です。取り下げれば、それも一緒に消えます。 このときは、消す前にいったん退避が取られていたので、実測の記録だけ拾って書き戻せました。助かったというより、**「捨てていい」と言った側の私が、何が入っているか把握していなかった**という話です。指示は一言でも、消えるものは一言では済まない。 **二つ目。告知を出した直後に、本命が見つかる。** 利用者向けの不具合告知を先に出しました。文面は「読み上げと通知が一時的に止まっていた」という内容で、事実として間違ってはいません。 その直後に、新バージョンが巻き戻されていたことが分かりました。順番が逆だったら、告知の文面は違っていたはずです。**結果的には、配布し直して実態が告知に追いついた**ので問題は無くなりましたが、これは運が良かっただけです。 外に出すものは取り消せません。「急いで出す」と「全体を把握してから出す」は、だいたい両立しません。 **三つ目。途中で安全装置に止められる。** 本番の設定ファイルを書き換えようとしたところ、途中で拒否されました。共有リソースを変更する操作だ、という理由です。 止められた瞬間は「今それどころじゃないんだけど」と思いました。ただ、あのとき止まったのは、**設定の修正と、動かすバージョンの変更を一度にやろうとした**ときです。分けてやり直したら通りました。結果としては、影響範囲の違う 2 つを混ぜるなという指摘で、正しかったことになります。 正しいけれど、障害の最中に言われると邪魔ではあります。この「正しいけど邪魔」は、たぶん無くならないし、無くさないほうがいいものです。 --- ## 結局、何が変わったのか 直したものを並べると、こうなります。 - 中継役が動かすプログラムを、名前で具体的に指定した。名札まかせをやめた - YouTube の認証情報を、設定ファイルに恒久的に書いた - ボットたちの状態確認の窓口を、外に出し直した - 新バージョンを配布し直した そのうえで、**同じ修正を、手元のソースコード側にも入れました。** ここが今回いちばん大事なところです。 今回の 2 つの原因は、どちらも「サーバー上で手作業で直したが、手元には反映していなかった」ものでした。だから、手元のものでサーバーを上書きするたびに、直したはずの設定が消えて元に戻る。**同じ事故が定期的に復活する仕掛けが、ずっと仕込まれたままだった**わけです。 「直した」と「もう起きない」は違う、という当たり前の話ですが、今朝はそれが 3 か月越しで回収された形になりました。 --- ## 締め 障害対応にAIが居ると楽です。楽ですが、楽さの中身は「代わりにやってくれる」ではありませんでした。 **見落としにくくなる**。バラバラに見えた複数の症状が、一度の更新作業から枝分かれしていたと分かったのは、全部を同時に並べて眺めたからです。そして**自分の過去の記録が効く**。今回の原因はどちらも、前の自分が「これは繰り返す」と書き残していたものでした。 そのかわり、**こちらが雑に指示すると、雑に実行されます。** 「捨てて」と言えば捨てるし、「出しといて」と言えば出します。判断の粗さは、そのまま結果の粗さになって返ってくる。かき乱されたと感じた場面は、よく見ると全部、私の指示が一言だった場面でした。 そしてもう一つ。この記事は、書き上がったあとに二度も前提を書き直しています。 一度目は「通知は来ていなかった」と書いていたのを訂正しました。実際には 6 件来ていた。二度目は「根拠のない勘で見にいった」と書いていたのを訂正しました。実際は通知を受けて、配布の日だと知っていて、見当をつけてから確認に入っている。**どちらも、私が確かめずに書いた思い込みです。** AIが居ようが居まいが、思い込みで書いた文章は思い込みのまま残ります。**「いや、通知は来てるよ」と言われるまで直らない。** そこは最後まで人の側の仕事でした。 朝 5 時に通知を受けて、7 時前には全部緑になっていました。通知は正しく届いていたので、異常があること自体は最初から分かっていたし、原因の見当もついていた。ただ、**その見当の先にあった症状が、一度の更新作業から枝分かれしていたと組み立てるところ**まで、あの時間にたどり着けたかというと、正直あやしいと思います。 --- ※この記事は 2026 年 9 月時点の構成と実装をもとにしています。サービス構成は今後変わる可能性があります。