私たちの会社では、18のポータルサイトに対してAIスタッフが毎日記事を自動生成する仕組みを構築している。Windows Task Schedulerに27本のタスクを登録し、深夜1時から早朝5時20分にかけて順番に記事生成パイプラインが走る。Tier A(主力ポータル)は毎日、Tier Dは週1回という具合に、優先度に応じたスケジュールを組んでいた。
構築した時点では「完成した」と思っていた。それが間違いの始まりだった。
SEO日次レポート廃止が引き起こした連鎖障害
2026年3月18日、SEO日次レポートの自動生成タスク(SEO-AutoPublish)を廃止する作業を行った。レポートの集約方式を変更することになり、古いタスク定義を削除したのだ。
問題は、この廃止作業のなかでTask Schedulerの操作を誤り、記事生成パイプライン全体の27タスクも一緒に消してしまったことにある。PowerShellスクリプト setup-portal-schedules.ps1 で一括登録していたタスクが、別の管理操作の巻き添えで全滅した。
ここで重要なのは、タスクが「エラーで停止した」のではなく「存在ごと消えた」という点だ。エラーなら何かしらのログが残る。しかし存在しないタスクはログすら生成しない。これがサイレントフェイルの本質であり、私たちが8日間気づけなかった根本原因だった。Microsoftのタスクスケジューラのドキュメントでも、タスクの削除操作に関する影響範囲の管理について注意喚起されている。
8日間、誰も気づかなかった構造的な理由
3月18日から3月26日まで、丸8日間にわたって18ポータルすべての記事自動生成が完全に停止していた。推定で80本以上の記事が生成されないまま時間だけが過ぎた。
なぜ誰も気づかなかったのか。理由は3つある。
まず、AIスタッフ体制では人間が毎日ダッシュボードを確認する運用になっていなかった。記事生成はAIに任せきりであり、「動いているはず」という前提で誰もチェックしていなかった。自動化の目的が「人手をかけない」ことにある以上、人間の目による監視に期待すること自体が構造的に矛盾している。
次に、生成された記事数を毎日カウントするような監視の仕組みがなかった。タスクスケジューラの実行ログは確認できるが、「今日はタスクが実行されなかった」ことを能動的に通知する仕組みは存在しなかった。動いているかどうかを知るには、自分から見に行くしかなかった。
そして3つ目に、記事が1日生成されなくても、ポータル自体はすでに公開済みの記事で正常に表示され続ける。サイトが落ちたわけではないから、外部からの異常検知も働かない。表面上は何も変わらず、水面下で新規コンテンツの供給だけが止まっていた。これはGoogleの検索品質ガイドラインが重視する「新鮮で有用なコンテンツ」の供給が途絶えたことを意味する。
発見のきっかけは「人間の違和感」だった
8日間の沈黙を破ったのは、システムからのアラートではなく、代表の京谷本人が「最近記事が少ない気がする」と気づいたことだった。
これは皮肉な話だ。自動化で人手を減らしたはずなのに、最終的に異常を検知したのは人間のカンだった。もし代表がたまたま記事の更新頻度を気にしていなければ、さらに何日も放置されていた可能性がある。
Task Schedulerを確認すると、記事生成関連の27タスクがすべて消えていた。原因を遡ると、SEO-AutoPublishの廃止作業にたどり着いた。廃止対象は1つのタスクだったはずが、操作のスコープが想定より広く、同一フォルダ配下の全タスクを巻き込んでいた。
復旧は一瞬だった——だからこそ問題が根深い
復旧自体は驚くほど簡単だった。setup-portal-schedules.ps1 を再実行するだけで、27タスクが一括で再登録された。Infrastructure as Code(IaC)の考え方でタスク登録をスクリプト化していたことが、ここでは功を奏した。
しかし、復旧が簡単だったことが逆に問題の根深さを示している。壊れやすく、かつ壊れたことに気づけない仕組みは、復旧が簡単であっても運用上のリスクは高い。復旧の容易さは「壊れても大丈夫」を意味しない。8日間分の損失は取り戻せないからだ。
この8日間で失われたものを概算すると、18ポータル×8日間で最大144本の記事生成機会が消えている。Tier構成を加味しても80本以上は確実だ。SEO観点では、検索エンジンへの新規コンテンツ供給が1週間以上途絶えたことで、クロール頻度の低下やインデックス鮮度の劣化が懸念される。コンテンツの更新頻度はクロールバジェットに直結する要因であり、特に新規ドメインのポータルでは致命的な遅れにつながりうる。
自動化パイプラインに必要な3層の監視体制
この経験から、自動化パイプラインには最低でも3層の監視体制が必要だと実感した。
第1層:実行ログの監視
タスクが実行されたかどうかを確認する最も基本的な層だ。Windows Task Schedulerの場合、イベントログに実行記録が残る。しかし前述のとおり、タスク自体が消えている場合はログも生成されない。この層だけでは今回のケースを検知できなかったことを認識しておく必要がある。
実行ログの監視を導入する際には、「ログがあること」ではなく「ログがないこと」を検知する設計にしなければならない。特定の時間帯に必ず実行されるはずのタスクが実行されていなければ、それ自体が異常シグナルだ。PrometheusのAbsent関数はまさにこの「存在しないことの検知」を実現するための仕組みであり、考え方として参考になる。
第2層:ヘルスチェック(成果物の検証)
タスクが実行されたとしても、正常に完了したかは別問題だ。記事生成パイプラインでいえば、「今日の記事がD1データベースに正しく格納されたか」を確認する層になる。
具体的には、毎朝6時(全タスク完了後)に前日分の記事数をカウントし、期待値との差分をチェックするスクリプトを用意する。Tier Aポータルなら毎日1本、Tier Bなら週3本といった期待値と実績を突合し、差分があればアラートを発報する仕組みだ。私たちのシステムでは、Cloudflare D1に記事を格納しているため、Wrangler CLIでSELECTクエリを発行するだけで前日の記事数を確認できる。技術的なハードルは低い。
第3層:死活監視(外部からの疎通確認)
内部の仕組みがすべて壊れていても機能する、最後の砦だ。外部の監視サービス(UptimeRobotやCloudflare Health Checksなど)から定期的にポータルサイトの最新記事更新日を確認し、一定期間更新がなければ通知する。
この層の価値は、内部のどこが壊れていても検知できる点にある。タスクスケジューラの障害、APIの障害、データベースの障害——原因を問わず「結果として記事が出ていない」という事実を外部から捕捉する。
「動いているはず」を排除するための設計原則
今回のインシデントから、自動化システムの設計原則を3つ定めた。
第一に、Fail Loudの原則だ。サイレントに失敗するシステムは最も危険だ。失敗したら必ず声を上げる——Slackへの通知、メールアラート、Discordへのwebhook送信など、複数の経路で「壊れた」と叫ぶ仕組みにする。正常時のログよりも、異常時の通知経路を先に設計するべきだ。
第二に、Heartbeatパターンの導入だ。各タスクが正常に完了するたびに、外部のエンドポイントに「生きている」信号を送る。信号が途絶えたら異常と見なす。これにより、タスクが消えた場合でも「信号が来なくなった」こと自体がアラートのトリガーになる。HeartbeatパターンはCI/CDパイプラインの健全性監視にも応用が効く汎用的な仕組みだ。
第三に、変更の影響範囲を限定するアーキテクチャだ。今回の事故は、1つのタスクを廃止する操作が27タスクに波及したことで起きた。タスクのグループ化、フォルダ分離、依存関係の明示化など、1つの操作が想定外の範囲に影響しない構造を設計段階で組み込む。マイクロサービスアーキテクチャでいう「障害の分離」と同じ発想だ。
京谷商会で実際に導入した改善策
インシデントを受けて、私たちは以下の改善を実施した。
Task Schedulerのタスクを機能別フォルダに分離した。記事生成パイプラインとSEOレポート関連タスクは別フォルダに配置し、一方の操作が他方に影響しない構造にした。これまでは利便性を優先して同一フォルダにまとめていたが、それが障害の伝搬経路になってしまった。
また、setup-portal-schedules.ps1 実行時にタスク一覧のスナップショットをJSONで出力し、Git管理下に置く運用を開始した。スケジューラの状態がコードとして管理されていれば、「いつ、何が変わったか」の差分追跡が可能になる。D1 Time Travelでデータベースの復元ができるように、スケジューラの状態もバージョン管理の対象にする考え方だ。
ヘルスチェックについては、毎朝6時にD1の記事テーブルを照会し、前日の生成数を確認するスクリプトを追加した。期待値を下回った場合はDiscordの #dev-内部 チャンネルに自動通知する。通知先をDiscordにしたのは、私たちのAIスタッフ体制では業務連絡がすべてDiscord経由で流れているため、既存の情報フローに載せることで見落としを防げるからだ。
自動化が進むほど「監視の自動化」が必須になる
AIスタッフ体制で93名から2,000名規模に拡大していく過程で、自動化のレイヤーはますます深くなっていく。記事生成だけでなく、メール処理、Slack応答、クラウドワークスの案件監視、LINE配信など、あらゆる業務が自動化されていく。
このとき見落としがちなのが、自動化した業務を監視する仕組み自体も自動化しなければならないという点だ。「人間が毎日チェックする」では、そもそも自動化した意味がない。監視も含めて自動化して初めて、運用として完成する。
以前の記事でAIスタッフ運用の7つの失敗を紹介したが、今回のインシデントは「8つ目の失敗」として最も示唆に富んでいる。構築時に考慮から漏れがちな「何もしないことの検知」——これが自動化パイプラインの最大の盲点だ。
SRE(Site Reliability Engineering)の世界では「オブザーバビリティ」という概念が定着している。Google SREの書籍では、モニタリングの4つのゴールデンシグナル(レイテンシ、トラフィック、エラー率、飽和度)が提唱されているが、私たちのケースでは5つ目のシグナルとして「不在(Absence)」を加えるべきだったと感じている。「何も起きていないこと」を異常として捉える視点は、特に自動化パイプラインでは不可欠だ。
この記事を読んだ人が来週からできること
自動化パイプラインを運用しているなら、まず1つだけ確認してほしい。
あなたのパイプラインが明日止まったとして、何日後にそれに気づけるだろうか。
答えが「わからない」か「たぶん数日は気づかない」であれば、今回紹介した3層監視のうち、まずは第2層のヘルスチェックから始めることをお勧めする。最も簡単な実装は、cron(またはTask Scheduler)で毎日1回、直近24時間の成果物の件数をカウントし、期待値と比較するスクリプトだ。差分があればSlackやメールに通知する。これだけで「サイレントフェイル」の大半を捕捉できる。
自動化の真の完成は、それが壊れたときに自動で気づける仕組みを備えた時点だ。構築して終わりではない。監視まで含めて設計し、定期的にテストし、そしてその監視自体も監視する。終わりのない入れ子構造に聞こえるかもしれないが、少なくとも「壊れていることに気づけない」状態からは脱却できる。
私たちは8日間の空白から、それを学んだ。