im_wower
·
2026-03-22
T-025-failover-rehearsal.md
1---
2task_id: T-025
3title: Failover rehearsal 与 Runbook
4status: done
5branch: feat/T-025-failover-rehearsal
6repo: /Users/george/code/baa-conductor
7base_ref: main@6505a31
8depends_on:
9 - T-019
10 - T-021
11 - T-022
12write_scope:
13 - docs/ops/**
14 - scripts/failover/**
15updated_at: 2026-03-22T02:16:15+0800
16---
17
18# T-025 Failover rehearsal 与 Runbook
19
20## 目标
21
22把当前主备设计推进到“有可执行 rehearsal 步骤和清晰运维 runbook”的程度。
23
24## 本任务包含
25
26- 在 `scripts/failover/**` 下补 failover rehearsal 辅助脚本
27- 在 `docs/ops/**` 下补 planned failover / emergency failover / switchback runbook
28- 把 Tailscale `100.x`、公网域名、launchd、Nginx 的配合关系写清楚
29
30## 本任务不包含
31
32- 修改 app 业务代码
33- 真实执行线上 failover
34- 修改 `baa-firefox`
35
36## 建议起始文件
37
38- `docs/ops/README.md`
39- `scripts/failover/`
40
41## 交付物
42
43- 可执行或半自动的 rehearsal 辅助脚本
44- 清晰的 failover 运维手册
45
46## 验收
47
48- 如果新增 shell 脚本:`bash -n scripts/failover/*.sh`
49- `git diff --check`
50- 文档里明确 planned / emergency / switchback 三种路径
51
52## 更新要求
53
54完成时更新 frontmatter 的:
55
56- `status`
57- `base_ref`
58- `updated_at`
59
60并补充下面这些内容:
61
62## files_changed
63
64- `coordination/tasks/T-025-failover-rehearsal.md`
65- `docs/ops/README.md`
66- `docs/ops/failover-topology.md`
67- `docs/ops/planned-failover.md`
68- `docs/ops/emergency-failover.md`
69- `docs/ops/switchback.md`
70- `scripts/failover/common.sh`
71- `scripts/failover/print-topology.sh`
72- `scripts/failover/rehearsal-check.sh`
73- `scripts/failover/print-checklist.sh`
74
75## commands_run
76
77- `npx --yes pnpm install`
78- `chmod +x scripts/failover/*.sh`
79- `bash -n scripts/failover/*.sh`
80- `./scripts/failover/print-topology.sh --env scripts/ops/baa-conductor.env.example`
81- `./scripts/failover/print-checklist.sh --scenario planned --env scripts/ops/baa-conductor.env.example`
82- `./scripts/failover/rehearsal-check.sh --env scripts/ops/baa-conductor.env.example --skip-public --skip-control-api`
83- `git diff --check`
84
85## result
86
87- 新增 `scripts/failover` 只读辅助脚本,用于输出主备拓扑、生成场景化 checklist,并对 public/direct/control-api 做 rehearsal 校验。
88- 在 `docs/ops` 下补齐 failover topology、planned failover、emergency failover、switchback 四份文档。
89- runbook 明确写清 Cloudflare DNS 固定到 VPS、VPS Nginx 回源 Tailscale `100.x`、节点 `launchd` 控制本地 conductor 存活,以及当前 Nginx 只按连通性而非 lease 感知切换。
90
91## risks
92
93- 当前 `GET /v1/system/state` 仍只返回扁平 `holder_id/mode/term/lease_expires_at`,脚本只能通过 `holder_id` 前缀推断 leader 节点。
94- 当前没有真正的 `promote/demote` 维护接口;planned failover 和 switchback 仍依赖 `pause/drain` 加本机 `launchctl bootout/reload`。
95- 如果 mini 仍可达但逻辑上不该接流量,公网入口可能仍命中 mini;emergency runbook 已记录这种情况下需要 VPS Nginx 热修。
96
97## next_handoff
98
99- 在真实节点或 staging 上按 runbook 做一次 dry-run / rehearsal,确认 `mini`、`mac`、VPS 三侧命令、权限和路径与文档一致。
100- 后续可补 `system.state` 的 leader host 字段,以及真正的 maintenance `promote/demote` API,减少对人工 `launchctl` 与 Nginx 热修的依赖。