Skip to content
Dan Ochoa.ノート一覧

Cronradar · アーキテクチャ

監視者を監視するのは誰か?

自分自身の障害を生き延びなければならない cron 監視サービスを作る — そのためにインフラの半分を削除した理由。

Cronradar

課題

Cronradar は、スケジュールされたジョブが静かに失敗した瞬間を知らせるために存在する。これは通常の信頼性の問いを逆転させる。この製品は他の何かがダウンしているときにだけ役に立ち、そして誰にも気づかれず静かに止まる存在に決してなってはならない。受け取ったエラーについては通知できない — エラーは存在しないからだ。届かなかった ping について通知する。つまりシステム全体が、期限に対する「不在」を検出するために作られている。

各モニターは、次に期待される ping の時刻と猶予期間を持つ。バックグラウンドの走査が期限を過ぎたモニターを探し、Warning から Critical へ移し、エスカレーションする。もう一つの走査は、作成されたのに一度も ping していないモニター — 報告を始めるはずが始めなかったジョブ — を扱う。不在には二つの形があり、どちらも時計に対して捕まえなければならない。

自動検出と、ドリフトの問題

5 行の統合は単に ping を送るだけではない — フレームワークの SDK(HangfireQuartz)が、アプリが実際に宣言したジョブをモニターへ突き合わせる。手動で登録するものは何もない。コード内のスケジュールが信頼できる情報源だ。

これは ping の取りこぼしより微妙な失敗を生む。スケジュールから完全に削除されたジョブだ。二度と ping しないので、素朴なモニターは永遠に通知し続ける。ドリフト走査は各ジョブが最後に宣言された時刻を追跡し、スケジュールから消えたジョブのモニターを自動的に一時停止する — 意図的にデフォルト無効のフラグの背後に置いている。モニターを黙って止めるのは、意図の読み違いがあれば本物の障害を隠しかねない、まさにその種の「親切な」振る舞いだからだ。

Redis と Typesense と同梱の DB を削除した理由

バックエンドは .NET(Aspire でオーケストレーション)と PostgresHangfire がスケジュール計算と走査を回す。最初からこう身軽だったわけではない。初期は RedisTypesensenginx、そして同梱の Postgres も動いていた。一度の作業でそれらをすべて剥ぎ取り、単一の共有ホスト型 Postgres に対して、すべてを Traefik 経由でルーティングした。

その理由が製品のテーゼそのものだ。追加の可動部品はどれも、他が壊れたときに動き続けることだけが仕事である唯一のサービスの上で、また一つ壊れうるものになる。整合性を保たねばならないキャッシュ、同期を保たねばならない検索インデックス、自分で運用せねばならないデータベース — それぞれが、信頼性ツールに持ち込む新たな故障要因だ。Postgres はすでに永続的でトランザクショナルな状態をうまく扱う。cron 監視の状態は小さく、リレーショナルだ。だから「なぜキュー / キャッシュ / 検索クラスタではないのか」への答えは、それらを動かした上で、壊れうるものを減らす方を選んだ、というものだ。

監視者を監視する

ping の取り込みはダッシュボードとは別の、それ自身のサービスとして動く。その分離が肝心だ。ジョブのハートビートを受け取る面は、グラフを描画したり課金を処理したりする面と運命を共有しない。だからダッシュボードの問題で ping を取りこぼすことはない。アラート、ping 取り込み、ダッシュボード更新の各経路は永続的実行のために堅牢化され、処理中のアラートは失われる代わりに再起動を生き延びる。

cron.life はジョブが成功時に叩くハートビートのエンドポイント、crontab.space は平易な言葉でのスケジュール作成ツール — Cronradar 自身の生存も顧客のジョブと同じやり方で確かめられる、そのための相棒だ。

数字が実際に語ること

エッジ(Traefik のアクセスログ)で約 3 週間計測: API・ハートビート取り込み・ダッシュボードのエンドポイント全体で、HTTP 応答の中央値 14 ms、p95 は約 97 ms、p99 は約 658 ms。これはプロキシで計測したエンドポイントの応答レイテンシ — Cronradar がリクエストに答える速さだ。

これはあえて、cron 監視のマーケティングが引用したい数字ではない。アラート配信の時間ではないからだ。アラートはプロキシを通らないバックグラウンドのジョブであり、「どれだけ速く気づいて知らせるか」を測るには ping 受信から通知送信までを計る必要がある。それは別の計測であり、速い応答時間で代用させるより、分けて報告するべきものだ。

14 msp50応答の中央値
97 msp95
658 msp99

次にやるなら変えること

今の正直な欠点はテストの網羅だ。SDK はテストされているが、サーバ側の走査ロジック — ジョブが遅延しているかを判定するまさにそのコード — は、最も重要な部品にしては手動の自信に頼りすぎている。「必ず気づく」を約束する製品にとって、取りこぼし検出の経路こそ、完成と呼ぶ前に、時計の境界・猶予期間の境界・夏時間の切り替えについてプロパティベースのテストを置きたい場所だ。

ノート一覧