Chaos Engineering Runbook
Parky スタックが想定外障害に耐えられるか、また検出・復旧フローが 実戦で機能するかを四半期ごとの game day で検証する。 本ドキュメントはシナリオ集、実施手順、記録テンプレートを 1 ファイルに集約した SSoT。
1. 目的
- 耐性検証 — Supabase / Cloudflare / 外部 API の単一障害点で、 Parky のユーザー体験がどこまで劣化するか (graceful degrade or hard fail) を実測。
- 検出フローの実地練習 — Sentry / synthetic-healthcheck / Discord P0/P1 alert / SLO burn auto-rollback が想定通り動くかを、実際に 壊して確認する (= ペーパーテストでは見えない gap を炙り出す)。
- 復旧時間 (MTTR) の計測 — 障害誘発から通知着弾、 rollback 完了までの実測時間を蓄積。SLO Phase 2 移行の判断材料に使う。
- 1 人開発期の "監視疲れ防止" — false-positive を避けつつ 本物の障害を見逃さない閾値を、game day での誤発火 / 見逃しから calibrate する。
2. 想定シナリオ
Parky の依存マップ (Cloudflare Workers BFF → Supabase / R2 / 外部 API) を踏まえ、 影響面が異なる 6 シナリオを最小セットとする。各 game day ではこの中から 3〜4 シナリオを選択して実施する (全部やると 1 日では終わらない)。
| # | シナリオ | 影響面 | 誘発手段 | 推奨環境 |
|---|---|---|---|---|
| S1 | Supabase DB 一時停止 | authenticated 全 path | Supabase Dashboard で project pause | dev |
| S2 | Hyperdrive 接続切断 | BFF DB 経由 path | wrangler secret rotate (一時的に invalid token) | dev |
| S3 | R2 障害 | 画像 / asset 配信 | R2 binding を invalid bucket に向ける | dev |
| S4 | CF Workers リージョン障害 | (global 自動 failover 確認) | 誘発不可、CF status を観測のみ | prod (受動) |
| S5 | 外部 API 障害 (Stripe / Resend / Mapbox) | 決済 / 通知 / 地図 | MSW で 5xx / timeout を mock | dev |
| S6 | Supabase Auth 障害 | session 維持 / 新規 login | Auth project 個別 pause | dev |
3. 各シナリオの実施手順
S1. Supabase DB 一時停止 P0 想定
事前準備
- 実施環境:
devまたはstg。prod では絶対に実施しない。 - on-call (= 全員) に Discord
#p2-deploysで 30 分前に告知。 - metric snapshot を取る:
- Sentry の error rate / p99 を直近 1 時間 screenshot。
- synthetic-healthcheck の最新成功 run を確認。
- auto-rollback-dev の最新 burn=healthy を確認。
scripts/deploy/rollback.sh api dev --dry-runで rollback ターゲットを事前確認。
障害誘発手順
- Supabase Dashboard →
parkydevproject → Settings → General → Pause project。 - 誘発時刻を
YYYY-MM-DD HH:MM JSTで記録 (秒単位)。 - 並行して
cd parky/api && npx wrangler tail --config wrangler.public.toml --env devでログ流し見 (4 split worker のうち public がメイン HTTP route 担当)。
期待される挙動
/healthz/readyが 503 +{ ok: false, checks: { db: 'fail' } }を返す。- synthetic-healthcheck workflow が連続 2 回 fail → Discord
#p1-opsに P1 通知。 - Sentry に
HyperdriveConnectionError系 event が発火 (DSN 設定済の場合)。 - auto-rollback-dev が次サイクルで burn=fast を返す可能性あり (synthetic fallback mode)。
この場合 rollback されるが rollback しても Supabase 自体が止まっているので解消しない。 これが想定通り (= rollback は app バグの是正であり、infra 障害には効かない) の確認。
復旧手順
- Supabase Dashboard → Resume project。
/healthz/readyが 200 OK に戻ることを確認 (5〜10 秒)。- synthetic-healthcheck の次 run で recovery 通知が
#p1-opsに出るか確認。 - auto-rollback-dev で誤発火していた場合は
scripts/deploy/rollback.sh api dev --version <original>で前進 deploy へ復帰。
S2. Hyperdrive 接続切断 P1 想定
事前準備
- 実施環境:
dev。 - 現在の Hyperdrive binding 値を
wrangler secret list --env devで控える (復旧用)。
障害誘発手順
echo "postgres://invalid:invalid@127.0.0.1:5432/none" | wrangler secret put HYPERDRIVE_URL --env devで invalid な接続文字列を投入。- または Cloudflare Dashboard → Hyperdrive → 該当 config を 一時 disable。
期待される挙動
- BFF の DB クエリが timeout / connection refused で落ちる。
- postgres.js v3 の自動再接続が走るがリトライ上限で諦める (Sentry に event)。
/healthz/readyが 503 を返す。
復旧手順
- 正しい
HYPERDRIVE_URLを再投入 (op-cache から取得 → wrangler secret put)。 - Cloudflare Hyperdrive config を re-enable。
- 5 分以内に healthz が回復することを確認。
S3. R2 障害 P2 想定
事前準備
- 実施環境:
dev。 - web/home / portal で画像が出ているページを 1 つ事前に開いておく (比較用)。
障害誘発手順
wrangler.tomlの R2 binding をbucket_name = "parky-nonexistent-test"に書き換えて dev へ deploy。- または既存 R2 bucket の API token を一時的に revoke。
期待される挙動
- 画像 endpoint が 404 / 502 を返す。
- BFF 本体は動き続ける (DB 系 endpoint は影響なし)。
- Astro home / portal admin の画像が壊れた alt text 表示になる (graceful degrade の検証)。
- Sentry に
R2NotFoundError系 event。/healthz/readyは 200 を返し続けるはず (= R2 は readiness に含めない設計確認)。
復旧手順
- wrangler.toml を git revert して再 deploy。
- 画像が再度表示されることを確認。
S4. Cloudflare Workers リージョン障害 受動観測
事前準備
- 誘発不可 (= CF 側でしか起こせない)。
- Cloudflare Status で Tokyo / Asia リージョンに incident が出ているタイミングを観察用に記録しておく。
観測ポイント
- CF Workers は global 自動 failover するので、特定リージョン障害で Parky 利用者には 遅延増加 として現れる (完全 outage にはならない)。
- Sentry で p99 latency が普段の 2 倍以上に振れるか観測。
- SLO burn check (auto-rollback-dev) が latency burn を返すかを確認。 ここで誤発火すると prod 自動 rollback の信頼性に直結するので 本シナリオは特に重要な calibration。
復旧手順
- 受動。CF 側の incident 解消を待つ。Parky 側は何もしない。
S5. 外部 API 障害 (Stripe / Resend / Mapbox) P1 想定
事前準備
- 実施環境:
dev+ MSW (Mock Service Worker) で fetch を intercept。 - 対象を 1 つに絞る (例:
api.stripe.com)。
障害誘発手順
- BFF の
fetchを MSW でhttps://api.stripe.com/*→ 503 / 30s timeout に書き換え。 - または Cloudflare Worker の
routesで該当ホストへの outbound を一時 reject。 - workflow_dispatch で
chaos-fault-inject.ymlを起動して Discord に開始通知。
期待される挙動
- 該当 endpoint (
/v1/billing/...) が 502 / 504 を返す。 - BFF が circuit breaker / retry-with-backoff をしているか確認 (現状は素通し想定)。
- Sentry に
StripeAPIErrorevent が出る。 - SLO burn (error rate × 3) が発火するか観測。
復旧手順
- MSW handler を解除して fetch を実 API に戻す。
- chaos-fault-inject.yml の duration 終了通知を待つ。
S6. Supabase Auth 障害 P0 想定
事前準備
- 実施環境:
dev。 - 新規 login と既存 session 維持の 2 種を分けて検証する。
- テスト用ブラウザを 2 つ用意 (既存 session / 未 login)。
障害誘発手順
- Supabase Dashboard → Auth → Policies で一時的に signin endpoint を block (= 大量 error 状態)。
- または Auth project だけ pause (DB と独立に止められる場合のみ)。
期待される挙動
- 新規 login: 5xx で失敗。
- 既存 session: BFF の session refresh が走るまでは動作。refresh で 5xx → silent logout される。
- Sentry に
AuthApiError多発。
復旧手順
- Auth policy を revert / Auth resume。
- 新規 login が回復することを確認。既存 session の自動再認証も観察。
4. 記録テンプレート
各 game day で以下の表を埋め、.work/parky/chaos/ 配下に
YYYY-MM-DD_chaos_game_day.md として保存する。
| 項目 | 値 |
|---|---|
| game day 日付 | YYYY-MM-DD HH:MM JST |
| シナリオ ID | S1 / S2 / S3 / S4 / S5 / S6 |
| 実施環境 | dev / stg |
| 実施者 | (name) |
| 誘発時刻 | HH:MM:SS |
| 1 次検出時刻 (Discord 着弾 or 手動気づき) | HH:MM:SS |
| 検出までの時間 (TTD) | N 分 N 秒 |
| 復旧開始時刻 | HH:MM:SS |
| 復旧完了時刻 (healthz 200 確認) | HH:MM:SS |
| 復旧までの時間 (TTR / MTTR) | N 分 N 秒 |
| 期待挙動との差分 | (自由記述) |
| 誤発火の有無 | あり / なし — 内容 |
| auto-rollback 動作 | (burn 種別 / rollback 実行可否 / 想定通りか) |
| 改善 action | 1) ... 2) ... (Issue 化必須) |
| 関連 PR / Issue | #xxxx |
5. 次回 game day 候補日
- 初回 (Phase 1 リリース直後 + 1 ヶ月) — Phase 1 ローンチ (2026-06 想定) の 1 ヶ月後。最初は S1 (DB 停止) と S5 (外部 API) の 2 シナリオに絞る。
- quarterly (四半期ごと) — 上記初回以降は 3 ヶ月に 1 回。 シナリオはローテーションで全 6 種を 1 年で回す。
- 非定期 — 大きな architecture 変更後 (例: postgres.js v4 移行, Cloudflare Pro upgrade, Phase 2 SLO 移行) は次回定期を待たず追加実施。
6. 整備すべき仕組み
game day を継続的に行うために以下を整備する。優先度順:
-
chaos-fault-inject workflow (skeleton) —
.github/workflows/chaos-fault-inject.ymlとして配置済。 現状は Discord に開始 / 終了通知を送るだけ。実際の障害誘発は manual。 将来 MSW / wrangler tail 連携で自動化する。 -
MSW (Mock Service Worker) — 外部 API mock の標準化。
BFF に MSW を組み込み、env
PARKY_CHAOS_MOCKSで有効化する仕組み。 (未実装 / S5 の game day 前に着手) - circuit breaker / retry-with-backoff — Stripe / Resend / Mapbox の outbound に共通 wrapper を入れて、 外部 API 障害時の cascading failure を防ぐ。 (未実装 / S5 の結果次第で着手判定)
- game day 記録の自動収集 — Discord channel / GitHub Actions の log から TTD / TTR を機械的に集計する script。 (Phase 2 入り後に着手)
7. 関連
- インシデント対応 — game day で発火した alert は 実 incident と同じトリアージ手順で扱う。
- Postmortem — 想定外の差分が出たら blameless postmortem を作成 (game day でも例外なく)。
- SLO / Error budget — burn rate 閾値の calibration source。
- Rollback runbook — auto-rollback と manual rollback の境界線。
- DR Drill (markdown) — 災害復旧訓練 (本書とは別レベル)。