Files
social-app/docs/plans/2026-02-24-runtime-refactor-plan.md
T
qzl 105cf82d21 fix: 恢复Celery配置 + 修复测试文件
- 恢复 CelerySettings 和相关计算属性
- 修复 celery/app.py 调用 configure_celery_app 参数
- 创建 core/initialization/init_data.py stub
- 删除不完整的 test_auth_supabase_gateway.py
2026-02-24 16:38:30 +08:00

634 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 运行时架构重构改动清单(Runtime Refactor Plan
**日期:** 2026-02-24
**作者:** AI Assistant
**状态:** Ready for Execution
## 审批状态流转(Release Readiness
| 状态 | 进入条件 | 退出条件 |
|---|---|---|
| Draft | 计划初稿创建完成 | 评审材料齐备并发起评审 |
| In Review | 架构/平台/后端评审已指派 Owner | 阻断项全部关闭 |
| Ready for Execution | 阻断项关闭,且满足本节“生效条件” | 任一生效条件失效,回退到 In Review |
| In Execution | 按 Phase 开始实施并产生变更记录 | 全部 Phase 完成并通过验收 |
| Completed | 验收、回滚演练、文档归档全部完成 | 无 |
### 当前状态
- `Ready for Execution`
### `Ready for Execution` 生效条件(必须同时满足)
-`AGENTS.md` 的 Compose 路径规范已与唯一标准对齐(`infra/docker/docker-compose.yml`),且校验命令通过。
- `runtime-bootstrap-gate` 已写入技术防绕过实施项(CI 依赖、统一执行器、自动检测)。
- 发布门禁、回滚演练、路由验收硬门槛已在计划内形成闭环,且命令可直接执行。
## 1. 标题与目的
### 1.1 重构目标
- 将长驻进程启动方式从 `infra/scripts/*.py` 包装脚本,迁移为编排层直接执行可观测命令(`uvicorn/gunicorn/celery`)。
- 将迁移/初始化从“混合入口脚本”改为 one-shot job(独立 CLI 命令 + Compose 一次性服务)。
- 配置策略从 `SOCIAL_RUNTIME__ENVIRONMENT` 分支控制,迁移为显式参数控制(web/worker 各自配置键)。
- Celery 从父进程拉多队列(`worker.py` 内部 `Popen`)改为按任务类型分组的独立 worker 服务。
### 1.2 非目标
- 不改动业务接口、领域逻辑、数据库 schema、Auth 流程。
- 不新增消息中间件类型(仍使用 Redis 作为 Celery broker/backend)。
- 不引入新的部署平台(仅调整当前 Docker Compose 运行路径)。
### 1.3 约束
- 仅调整运行时与运维启动路径,保持 API 行为兼容。
- 保持 `backend/src/core/config/settings.py` 作为唯一环境变量入口。
- 不在后端运行时代码中新增 `os.environ` 直读。
- 迁移期间允许“双轨短期兼容”,legacy 脚本至少保留一个发布周期(定义为一个正式版本迭代窗口)。
- legacy 脚本删除作为独立里程碑执行,不与入口切换同批发布。
### 1.4 验收标准
- 发布门禁:`init-job bootstrap` 成功(exit code=0)是 `web/worker` 启动前置条件,未通过禁止发布。
- 发布门禁唯一入口:本地与 CI 统一执行 `runtime-bootstrap-gate`,禁止任何绕过 gate 的 `up web/worker-*`
- Compose 可直接拉起 web 与分组 worker(至少 `critical/default/bulk` 三组),且均通过健康/存活检查。
- `SOCIAL_RUNTIME__ENVIRONMENT` 不再决定 web 入口类型(gunicorn/uvicorn 由显式开关控制)。
- 新旧配置并存期遵循“新键优先、旧键告警、版本截止”规则(见第 6 节)。
#### 1.4.1 可测门槛(必须全部满足)
执行上下文约束:所有 Python 命令统一在仓库根目录执行,并显式携带 `PYTHONPATH=backend/src`;禁止切换为 `cd backend` 写法。
| 类别 | 必跑命令/检查 | 通过门槛 |
|---|---|---|
| 发布门禁 | `docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap` | exit code = 0 |
| 启动验证(强制经 gate | `make runtime-bootstrap-gate && docker compose --env-file .env -f infra/docker/docker-compose.yml ps` | 两条命令 exit code = 0,且 `ps``web/worker-critical/worker-default/worker-bulk/redis/db` 均为 Up |
| 健康检查 | `curl -fsS http://127.0.0.1:8000/health` | exit code = 0 |
| Unit 测试 | `PYTHONPATH=backend/src uv run pytest backend/tests/unit/test_process_settings.py backend/tests/unit/core/runtime/test_cli.py -q` | exit code = 0 |
| Integration 测试 | `PYTHONPATH=backend/src uv run pytest backend/tests/integration -q` | exit code = 0 |
| E2E 最小链路 | `PYTHONPATH=backend/src uv run pytest backend/tests/e2e/test_infra_health_e2e.py -q` | exit code = 0 |
| 覆盖率门槛 | `PYTHONPATH=backend/src uv run pytest backend/tests/unit backend/tests/integration --cov=backend/src --cov-report=term-missing --cov-fail-under=80` | 覆盖率 >= 80%exit code = 0 |
### 1.4.2 Gate 与命令使用边界(消除绕过歧义)
| 命令类型 | 允许命令 | 使用场景 | 约束 |
|---|---|---|---|
| 发布/上线(唯一入口) | `make runtime-bootstrap-gate`(内部固定执行 `init-job bootstrap` -> `up web/worker-*`) | 本地发布、CI、手工发布、验收 | 必须使用;禁止在 gate 之外直接执行 `up web/worker-*` |
| 演练/排障(非发布) | `docker compose ... up -d web worker-critical worker-default worker-bulk redis db``docker compose ... logs ...``docker compose ... ps` | 故障复现、回滚演练、压测、本地调试 | 必须在 runbook 标注为“演练/排障命令”;不得作为发布放行依据 |
判定规则:任何“发布成功”结论都必须包含 `runtime-bootstrap-gate` 成功记录;仅执行直接 `up web/worker-*` 的记录一律判定为不合规。
### 1.4.3 路由验收硬门槛(必须满足)
| 类别 | 必跑命令/检查 | 通过门槛 |
|---|---|---|
| 路由用例(critical | `PYTHONPATH=backend/src uv run pytest backend/tests/integration/test_celery_routing.py::test_route_critical_task_to_critical_queue -q` | exit code = 0,断言命中 `critical` 队列 |
| 路由用例(default | `PYTHONPATH=backend/src uv run pytest backend/tests/integration/test_celery_routing.py::test_route_default_task_to_default_queue -q` | exit code = 0,断言命中 `default` 队列 |
| 路由用例(unknown -> default + 告警) | `PYTHONPATH=backend/src uv run pytest backend/tests/integration/test_celery_routing.py::test_route_unknown_task_to_default_with_warning -q` | exit code = 0,断言未知任务落到 `default` 且产生日志告警 |
| 路由验收判定 | `PYTHONPATH=backend/src uv run pytest backend/tests/integration/test_celery_routing.py::test_route_critical_task_to_critical_queue backend/tests/integration/test_celery_routing.py::test_route_default_task_to_default_queue backend/tests/integration/test_celery_routing.py::test_route_unknown_task_to_default_with_warning -q` | 三条用例均通过;`critical/default` 命中正确;unknown 路由不失败且有告警 |
## 2. 影响面清单(按文件)
说明:以下为本次重构的**目标改动清单**,按 Create / Modify / Delete 分类。
### 2.1 Create
| 文件路径 | 用途 |
|---|---|
| `backend/src/core/runtime/cli.py` | one-shot 运行命令入口(migrate/init-data |
| `backend/tests/unit/core/runtime/test_cli.py` | CLI 参数与流程单测 |
| `docs/runtime/runtime-runbook.md` | 新运行方式(web/worker/job)操作手册 |
### 2.2 Modify
| 文件路径 | 变更说明 |
|---|---|
| `infra/docker/docker-compose.yml` | 新增/改造 `web``worker-critical``worker-default``worker-bulk``init-job` 服务及依赖 |
| `backend/src/core/config/settings.py` | 新增显式 web/worker 配置模型,弱化 `runtime.environment` 分支语义 |
| `backend/src/core/celery/app.py` | 增加队列路由配置与默认队列策略,适配分组 worker |
| `backend/AGENTS.md` | 在 Phase 0 提前更新运行入口说明(从脚本切换到编排层直启 + one-shot job |
| `.env.example` | 新增显式启动参数,保留兼容期映射说明 |
| `backend/tests/unit/test_process_settings.py` | 更新设置项断言(显式参数优先) |
### 2.3 DeprecatePhase 0-4
| 文件路径 | 处理方式 |
|---|---|
| `infra/scripts/web.py` | 标记 deprecate,保留一个发布周期,不做物理删除 |
| `infra/scripts/worker.py` | 标记 deprecate,保留一个发布周期,不做物理删除 |
| `infra/scripts/bootstrap.py` | 标记 deprecate,保留一个发布周期,不做物理删除 |
| `backend/tests/unit/infra/test_web_script.py` | 标记 deprecate,保留到 Phase 5 |
| `backend/tests/unit/infra/test_worker_script.py` | 标记 deprecate,保留到 Phase 5 |
### 2.4 Delete(仅 Phase 5
| 文件路径 | 删除原因 |
|---|---|
| `infra/scripts/web.py` | deprecate 窗口结束后物理删除 |
| `infra/scripts/worker.py` | deprecate 窗口结束后物理删除 |
| `infra/scripts/bootstrap.py` | deprecate 窗口结束后物理删除 |
| `backend/tests/unit/infra/test_web_script.py` | 随 legacy 脚本物理删除一并移除 |
| `backend/tests/unit/infra/test_worker_script.py` | 随 legacy 脚本物理删除一并移除 |
## 3. 分阶段改造计划
## Phase -1:规范对齐阻断项(必须先完成,0.25 天)
### 变更项(强制前置)
- 修订根 `AGENTS.md` 的 Docker Compose 示例路径:从 `docker/docker-compose.yml` 统一为 `infra/docker/docker-compose.yml`
- 明确“单一规范”:仓库所有文档/脚本/CI 示例仅允许 `docker compose --env-file .env -f infra/docker/docker-compose.yml ...`
- 将该项设置为 Phase 0 之前的硬门禁;未完成不得进入 runtime 重构实施。
### 验收检查命令(强制)
```bash
rg -n "docker compose .* -f docker/docker-compose.yml" AGENTS.md docs/ infra/ backend/
rg -n "docker compose .* -f infra/docker/docker-compose.yml" AGENTS.md
docker compose --env-file .env -f infra/docker/docker-compose.yml config
```
### 通过判定
- 第一条命令无输出(无旧路径残留)。
- 第二条命令命中根 `AGENTS.md`
- 第三条命令 exit code = 0。
## Phase 0:基线冻结与兼容窗口(0.5 天)
### 变更项
-`docs/runtime/runtime-runbook.md` 记录当前启动命令基线与回滚命令。
- 前移更新 `backend/AGENTS.md`:将“脚本入口”改为“编排层直启 + one-shot job”。
- 统一 Compose 文件路径:仅允许 `infra/docker/docker-compose.yml`,修订范围包括 `AGENTS.md`、runbook、`.env.example`、CI 脚本/文档示例。
- 约定兼容窗口:先引入新入口并灰度验证,再删除脚本入口。
### 风险点
- 团队并行开发期间继续调用旧入口,导致“看似可用、实际分叉”。
### 回滚策略
- 仅文档与约定变更,回滚为恢复旧 runbook 即可。
### 验证命令
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml config
PYTHONPATH=backend/src uv run pytest backend/tests/unit/test_process_settings.py -q
```
### 验收方式
- 文档闭环(量化):`rg -n "docker compose .* -f docker/docker-compose.yml" AGENTS.md docs/ infra/ backend/` 无输出,且 `rg -n "docker compose .* --env-file .env -f infra/docker/docker-compose.yml" AGENTS.md backend/AGENTS.md docs/runtime/runtime-runbook.md .env.example` 命中 >= 4。
- 规范闭环(量化):`rg -n "runtime-bootstrap-gate|init-job bootstrap.*前置|禁止.*up web/worker" backend/AGENTS.md docs/runtime/runtime-runbook.md` 命中 >= 2,且命中内容覆盖“前置 + 禁绕过”两类语义。
## Phase 1Web 进程直连编排层(1 天)
### 变更项
- `infra/docker/docker-compose.yml` 新增/调整 `web` 服务:
- `command` 直接执行 `uv run uvicorn app:app ...`dev)或 `uv run gunicorn app:app ...`prod-like)。
- `working_dir` 指向 `backend/``PYTHONPATH=/app/backend/src`(按容器挂载实际路径)。
- `backend/src/core/config/settings.py` 新增显式键(示例):
- `SOCIAL_WEB__SERVER=uvicorn|gunicorn`
- `SOCIAL_WEB__HOST``SOCIAL_WEB__PORT`
- `SOCIAL_WEB__RELOAD`
- `SOCIAL_WEB__GUNICORN__WORKERS`
- 去除“仅 prod 走 gunicorn”的硬编码分支依赖。
### 风险点
- `working_dir/PYTHONPATH` 不一致导致 `app` 模块加载失败。
- gunicorn 与 uvicorn 参数映射不一致,造成性能/稳定性偏差。
### 回滚策略
- 保留 `web-legacy` profile(临时)可切回 `uv run python infra/scripts/web.py`
- 回滚 `settings.py` 新字段,恢复 `app+gunicorn+runtime.environment` 逻辑。
### Legacy 回滚资产(硬前置)
- 落地 `legacy` profile 资产:`bootstrap-legacy``web-legacy``worker-legacy` 三个服务必须可启动且命令固定。
-`docs/runtime/runtime-runbook.md` 固化 legacy 回滚步骤、期望结果、故障排查项。
- 产出并归档一次演练记录(时间、执行人、命令、日志路径、结果、问题单链接)。
### Phase 1 DoD(新增硬门槛)
- `web` 新入口通过第 1.4.1 的发布门禁与健康检查。
- legacy profile 资产已落地并可执行:`docker compose --env-file .env -f infra/docker/docker-compose.yml --profile legacy config` 返回 0。
- **必须完成一次第 14 节回滚演练并留档;未留档不得进入 Phase 2。**
### 验证命令(第 2-4 条仅用于演练/排障,非发布放行)
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d web redis db
docker compose --env-file .env -f infra/docker/docker-compose.yml logs web --tail=200
curl -fsS http://127.0.0.1:8000/health
```
### 发布门禁
-`init-job bootstrap` 非 0 退出码,禁止启动 `web` 并阻断发布流程。
## Phase 2:迁移/初始化 one-shot job 化(1 天)
### 变更项
- 创建 `backend/src/core/runtime/cli.py`,提供子命令:
- `migrate`(执行 alembic upgrade head
- `init-data`(调用 `core.initialization.init_data.initialize_data`
- `bootstrap`(按顺序执行 migrate + init-data
- Compose 新增 `init-job``docker compose run --rm init-job bootstrap`)。
- 设定强制门禁:仅允许在 `bootstrap` 成功后启动 `web/worker`
- `infra/scripts/bootstrap.py` 标记 deprecate 并移出主路径(删除延后至 Phase 5)。
### 风险点
- CLI 中同步/异步调用混用导致退出码不准确。
- 迁移 job 与 web 同时启动出现竞态。
### 回滚策略
- 保留 `bootstrap-legacy` profile(短期)可回退旧脚本。
- 若 job 失败,恢复旧 `bootstrap.py` 并维持“初始化先行”的启动前置条件。
### 验证命令
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job migrate
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job init-data
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap
```
## Phase 3Celery 队列分组与独立服务(1.5 天)
### 变更项
- `infra/docker/docker-compose.yml` 拆分 worker 服务:
- `worker-critical` -> `--queues=critical`
- `worker-default` -> `--queues=default`
- `worker-bulk` -> `--queues=bulk`
- `backend/src/core/config/settings.py` 增加队列分组显式配置:
- `SOCIAL_WORKER__GROUPS__CRITICAL__CONCURRENCY`
- 每组支持 `pool/time_limit/prefetch_multiplier/max_tasks_per_child`
- `backend/src/core/celery/app.py`
- `task_default_queue` 固定显式默认值(建议 `default`
- 增加 `task_routes`(按任务名前缀或模块路由)
- 统一异常策略:未知任务路由默认回落 `default`,并输出结构化告警(`event=celery.route.fallback`
- 保持 `task_create_missing_queues=False`(避免拼写错误静默自动建队列)
- `infra/scripts/worker.py` 标记 deprecate(父进程多子 worker 模式退役,删除延后至 Phase 5)。
### 风险点
- 无任务路由策略时任务可能全部落到默认队列,造成优先级失效。
- 队列切分后并发参数不当,导致 CPU 抖动或长尾任务阻塞。
- 缺少统一指标阈值会导致“已拆分但不可观测”。
### 回滚策略
- 暂保留 `worker-legacy` profile,以单 worker 多队列方式兜底。
- 发现路由异常时,临时将 `task_routes` 回退为全量默认队列。
### 验证命令(仅演练/排障,发布必须走 `make runtime-bootstrap-gate`
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d worker-critical worker-default worker-bulk redis
docker compose --env-file .env -f infra/docker/docker-compose.yml ps
docker compose --env-file .env -f infra/docker/docker-compose.yml logs worker-critical --tail=120
docker compose --env-file .env -f infra/docker/docker-compose.yml logs worker-default --tail=120
docker compose --env-file .env -f infra/docker/docker-compose.yml logs worker-bulk --tail=120
```
### 压测与回归要求
- 必须先完成第 15 节并发基线压测,再冻结 `SOCIAL_WORKER__GROUPS__*` 默认值。
## Phase 4:收口与发布门禁固化(0.5 天)
### 变更项
- 固化不可绕过门禁:`init-job bootstrap` 作为 CI 必经 job`runtime-bootstrap-gate`),`deploy` job 必须 `needs: [runtime-bootstrap-gate]`,gate 失败即终止流水线并禁止后续 `web/worker` 启动与发布步骤。
- 发布脚本与手工发布流程必须先显式执行 `docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap`,不得依赖 one-shot `depends_on` 语义来隐式放行。
- 新增本地统一执行器:`infra/scripts/runtime-bootstrap-gate.sh``make runtime-bootstrap-gate`(仅封装执行顺序,不改变主入口策略)。
- `docs/runtime/runtime-runbook.md` 新增“绕过风险”章节:直接执行 `up web/worker-*` 的风险、排障影响、审计追踪缺失。
- 新增 CI 自动检测绕过检查:若在 gate 之外检测到直接 `up web/worker-*`,流水线失败。
- 更新 runbook、`.env.example` 与 CI 指南,确保新入口一致。
- 补充容器化 smoke 流程到 CI,覆盖 `worker-critical/default/bulk` 三组。
### `runtime-bootstrap-gate` 唯一执行入口(本地/CI共用)
```bash
bash -euo pipefail -c '
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d web worker-critical worker-default worker-bulk redis db
'
```
- 以上模板是唯一允许的串行入口:第一条命令非 0 时 shell 立即退出,第二条 `up web/worker-*` 不得执行。
- 本地手工执行、发布脚本、CI stage 均必须复用同一模板(stage 名称固定 `runtime-bootstrap-gate`)。
### 技术防绕过校验命令(强制)
```bash
rg -n "runtime-bootstrap-gate" .github/workflows
rg -n "needs:\s*\[?runtime-bootstrap-gate\]?" .github/workflows
rg -n "docker compose .*up -d .*\b(web|worker-critical|worker-default|worker-bulk)\b" .github/workflows
rg -n "runtime-bootstrap-gate" Makefile infra/scripts docs/runtime/runtime-runbook.md
```
判定规则:
- `deploy` 相关 job 必须显式依赖 `runtime-bootstrap-gate`
- 直接 `up web/worker-*` 仅允许出现在 gate 执行器(脚本或 Make target)中;若出现在其他 CI job,判定为绕过并阻断。
### 风险点
- 文档未同步导致新成员仍按旧命令启动。
### 回滚策略
- 若发布窗口紧,维持 legacy 脚本 deprecate 状态并延后删除。
### 验证命令(第 4-6 条仅演练/排障;发布放行看 gate 记录)
```bash
PYTHONPATH=backend/src uv run pytest backend/tests/unit -q
PYTHONPATH=backend/src uv run pytest backend/tests/integration -q
PYTHONPATH=backend/src uv run pytest backend/tests/e2e/test_infra_health_e2e.py -q
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d web worker-critical worker-default worker-bulk redis db
curl -fsS http://127.0.0.1:8000/health
```
## Phase 5legacy 删除里程碑(独立发布周期后,0.5 天)
### 触发条件
- 新入口已稳定运行至少一个发布周期。
- 第 14 节回滚演练最近一次结果为通过。
### 变更项
- 删除 `infra/scripts/web.py``infra/scripts/worker.py``infra/scripts/bootstrap.py`
- 删除 `backend/tests/unit/infra/test_web_script.py``backend/tests/unit/infra/test_worker_script.py`
- 清理文档中所有 legacy 命令。
### 回滚策略
- 若删除后发现阻塞,可从发布标签恢复 legacy 脚本并回滚到上一版本镜像。
### 验证命令
```bash
PYTHONPATH=backend/src uv run pytest backend/tests/unit backend/tests/integration -q
docker compose --env-file .env -f infra/docker/docker-compose.yml config
```
## 4. 详细改动清单(Checklist,按优先级)
- [ ] **P0-1:新增 runtime CLI one-shot 命令入口**
DoD`PYTHONPATH=backend/src uv run python -m core.runtime.cli migrate|init-data|bootstrap` 均返回正确 exit code`init-data` 调用 `initialize_data()`
预计影响:替换 `bootstrap.py`,降低混合脚本复杂度。
- [ ] **P0-0:根 AGENTS Compose 路径规范修订(强制前置)**
DoD:根 `AGENTS.md` 已统一为 `infra/docker/docker-compose.yml`;全仓无 `docker/docker-compose.yml` 启动示例残留;`docker compose ... config` 校验通过。
预计影响:消除规范冲突,避免运行入口歧义。
- [ ] **P0-2Compose 新增 `init-job` 并接入 one-shot 流程**
DoD`docker compose run --rm init-job bootstrap` 可重复执行(幂等)且 exit code=0;该步骤失败时禁止启动 `web/worker`
预计影响:迁移/初始化路径标准化,便于 CI/CD 执行。
- [ ] **P0-3Compose 直启 web,移除对 `web.py` 依赖**
DoD`web` 容器命令不再包含 `infra/scripts/web.py`;且启动前已通过 `init-job bootstrap``/health` 可用。
预计影响:减少一层 Python 子进程包装,排障路径更直接。
- [ ] **P0-4:前移更新 `backend/AGENTS.md` 与 Compose 路径统一闭环**
DoD`backend/AGENTS.md` 已改为新入口规范;仓库文档/脚本示例统一为 `infra/docker/docker-compose.yml`
预计影响:降低路径歧义与误启动概率。
- [ ] **P1-1:显式 web 配置键落地(`SOCIAL_WEB__*`**
DoD`SOCIAL_RUNTIME__ENVIRONMENT` 修改不再影响 web server 选型;选型由 `SOCIAL_WEB__SERVER` 控制。
预计影响:配置可预测性提升,环境分支耦合降低。
- [ ] **P1-2worker 拆分为 `critical/default/bulk` 独立服务**
DoDCompose 中存在 3 个 worker 服务,均只消费各自队列且日志区分明确。
预计影响:任务隔离增强,避免高耗时任务拖慢关键任务。
- [ ] **P1-3:Celery 路由显式化并禁用自动建队列**
DoD`task_routes` 生效,未知任务默认回落 `default` 且输出 `celery.route.fallback` 告警,`task_create_missing_queues=False` 仍生效。
预计影响:线上路由错误可提前暴露,运行风险可控。
- [ ] **P2-1:删除 legacy 脚本与脚本单测**
DoD:该项仅在 Phase 5(独立里程碑)执行;满足“保留一个发布周期 + 回滚演练通过”后才可移除。
预计影响:技术债下降,入口唯一化。
- [ ] **P2-2:更新文档与 env 模板**
DoD`backend/AGENTS.md``.env.example``docs/runtime/runtime-runbook.md` 三处命令一致。
预计影响:降低 onboarding 成本与误操作概率。
## 5. 队列拆分策略
### 5.1 推荐分组
- `critical`:用户同步感知任务(验证码发送、鉴权后置关键动作),目标低延迟。
- `default`:常规异步任务(中等耗时,可容忍轻微排队)。
- `bulk`:批处理/重计算/可延迟任务(高耗时、吞吐优先)。
### 5.2 何时需要“一队列一服务”
- 单任务类型 P95 执行时长显著高于其他任务(>3x)。
- 任务资源模型明显不同(CPU 密集 vs IO 密集)。
- 任务失败重试会产生级联影响,需要隔离故障域。
- 业务优先级强约束(SLA 严格,不能被普通任务占满并发)。
### 5.3 建议默认并发(起步值)
- `critical`: `concurrency=2~4`, `prefetch_multiplier=1`
- `default`: `concurrency=2`
- `bulk`: `concurrency=1~2`, `max_tasks_per_child` 较小以抑制内存膨胀
## 6. 配置迁移表(旧 -> 新)
| 旧配置 | 新配置 | 迁移说明 |
|---|---|---|
| `SOCIAL_RUNTIME__ENVIRONMENT=prod` + `SOCIAL_GUNICORN__ENABLED_IN_PROD=true` | `SOCIAL_WEB__SERVER=gunicorn` | server 选型不再依赖 environment 分支 |
| `SOCIAL_APP__HOST` | `SOCIAL_WEB__HOST` | web 显式命名,避免与业务 app 配置混淆 |
| `SOCIAL_APP__PORT` | `SOCIAL_WEB__PORT` | 同上 |
| `SOCIAL_APP__RELOAD` | `SOCIAL_WEB__RELOAD` | reload 仅用于开发态 web 进程 |
| `SOCIAL_GUNICORN__WORKERS` | `SOCIAL_WEB__GUNICORN__WORKERS` | 参数归并到 web 维度 |
| `SOCIAL_WORKER__ENABLED_QUEUES=[...]` | Compose 服务拆分(`worker-critical/default/bulk`+ `SOCIAL_WORKER__GROUPS__*` | 去掉父进程多队列拉起模式 |
| `infra/scripts/bootstrap.py --migrate/--init-data` | `PYTHONPATH=backend/src uv run python -m core.runtime.cli migrate/init-data/bootstrap` | one-shot job 统一命令入口 |
| `SOCIAL_RUNTIME__SERVICE_NAME`(脚本注入) | Compose `service` 名称 + logging `service_name` 显式传参 | 不再依赖脚本注入环境变量 |
### 6.1 新旧配置并存规则(强制)
- 优先级:新配置键(`SOCIAL_WEB__*``SOCIAL_WORKER__GROUPS__*`)优先于旧键;若同时存在,以新键为准。
- 告警:检测到旧键生效或新旧同设时,启动日志输出 `DEPRECATION WARNING`(包含键名、替代键、截止版本)。
- 兼容截止版本:旧键兼容保留至 `v0.9`,自 `v1.0` 起移除旧键解析。
- 冲突处理:若新旧键值冲突,以新键执行并记录一次结构化告警事件(含 service_name 与环境)。
## 7. 测试策略(最小可执行集)
### 7.1 Unit
- 保留并扩展:`backend/tests/unit/test_process_settings.py`(新配置解析与默认值)。
- 新增:`backend/tests/unit/core/runtime/test_cli.py`(CLI 子命令、错误码、调用顺序)。
- legacy 保留期:`backend/tests/unit/infra/test_web_script.py``backend/tests/unit/infra/test_worker_script.py` 标记 deprecate,随 Phase 5 删除。
### 7.2 Integration
- 新增/调整:验证 Celery 路由配置可将任务落入预期队列(至少 `default``critical`)。
- 校验 one-shot `bootstrap` 流程在测试 DB 可重复执行且无副作用异常。
### 7.3 E2E
- 保底保留:`backend/tests/e2e/test_infra_health_e2e.py`
- 增加最小链路:`init-job -> web health -> worker process alive`
### 7.4 容器化 smoke(必须)
说明:此处 `up` 命令仅用于 smoke 与排障,不可替代 `runtime-bootstrap-gate` 发布门禁。
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d web worker-critical worker-default worker-bulk redis db
curl -fsS http://127.0.0.1:8000/health
docker compose --env-file .env -f infra/docker/docker-compose.yml ps
```
## 8. 交付物清单
### 8.1 文档
- `docs/runtime/runtime-runbook.md`(新增)
- `backend/AGENTS.md`(更新运行入口说明)
- `.env.example`(新增显式配置键与迁移注释)
### 8.2 配置
- `infra/docker/docker-compose.yml`(新增 web/worker 分组/init-job 服务)
- `backend/src/core/config/settings.py`(新增 web/worker 显式配置结构)
- `backend/src/core/celery/app.py`(显式路由与默认队列)
### 8.3 脚本/代码
- `backend/src/core/runtime/cli.py`(新增)
- `infra/scripts/web.py``infra/scripts/worker.py``infra/scripts/bootstrap.py` 先标记 deprecatePhase 5 删除
### 8.4 测试
- 新增 `backend/tests/unit/core/runtime/test_cli.py`
- `backend/tests/unit/infra/test_web_script.py` 随 Phase 5 删除
- `backend/tests/unit/infra/test_worker_script.py` 随 Phase 5 删除
- 更新 `backend/tests/unit/test_process_settings.py`
## 9. 主要风险与缓解
| 风险 | 影响 | 概率 | 缓解 |
|---|---|---|---|
| 入口切换后容器启动失败(路径/模块解析) | 高 | 中 | Phase 1 保留 legacy profile;先 `compose config` 再灰度起服务 |
| 队列路由配置缺失或漂移导致关键任务降级 | 高 | 中 | 统一 unknown->default+告警策略;增加 `test_route_unknown_task_to_default_with_warning` 并接入告警阈值 |
| 迁移 job 与 web 启动竞态 | 中 | 中 | CI 必经 `runtime-bootstrap-gate` 串行执行,`bootstrap` 成功后才允许 `up web/worker-*` |
| 文档与真实命令不一致 | 中 | 高 | Phase 4 强制三处文档一致性检查(AGENTS/runbook/.env.example |
## 10. 预计工作量
| 阶段 | 预计耗时 |
|---|---|
| Phase -1 | 0.25 天 |
| Phase 0 | 0.5 天 |
| Phase 1 | 1 天 |
| Phase 2 | 1 天 |
| Phase 3 | 1.5 天 |
| Phase 4 | 0.5 天 |
| Phase 5 | 0.5 天(独立里程碑) |
| **总计** | **5.25 天(含独立里程碑)** |
## 11. 已决策项(含验收条件 / Owner / 截止版本)
| 决策项 | 已决策内容 | 验收条件 | Owner | 截止版本 |
|---|---|---|---|---|
| 运行门禁固化 | `init-job bootstrap` 为 CI 必经 job`runtime-bootstrap-gate`),失败即终止 | CI 日志可见 gate job;当 `bootstrap` 非 0 时流水线终止且不执行 `up web/worker-*` | Platform/Infra | `v0.9` |
| Celery 路由最小策略 | 采用任务前缀路由(`tasks.critical.*` -> `critical`,其余默认 `default`)并保留 `bulk` 显式路由位;未知任务统一回落 `default` + 结构化告警 | integration 用例验证 `critical/default/unknown->default`;告警可检索 | Backend | `v0.9` |
| Compose 路径统一 | 全仓命令统一 `--env-file .env -f infra/docker/docker-compose.yml` | AGENTS、runbook、`.env.example`、CI 命令均一致且无旧路径残留 | Platform/Infra | `v0.9` |
| Gate 防绕过机制 | CI `deploy` 必须依赖 `runtime-bootstrap-gate`;本地/CI 统一执行器;绕过自动检测阻断 | 依赖关系可检索、绕过检查命令通过、runbook 已标注绕过风险 | Platform/Infra | `v0.9` |
## 12. 标准 CLI 调用规范(本地/容器/CI)
### 12.1 统一约束
- `docker compose` 固定使用:`--env-file .env -f infra/docker/docker-compose.yml`
- Python 命令统一在仓库根目录执行,不使用 `cd backend`
- `PYTHONPATH` 统一为:本地与 CI 使用 `backend/src`;容器内使用 `/app/backend/src`
### 12.2 本地开发(host
```bash
PYTHONPATH=backend/src uv run python -m core.runtime.cli bootstrap
PYTHONPATH=backend/src uv run uvicorn app:app --app-dir backend/src --host 0.0.0.0 --port 8000 --reload
PYTHONPATH=backend/src uv run celery -A core.celery.app worker --workdir backend/src --queues=default --loglevel=INFO
```
### 12.2.1 本地统一门禁(必须)
```bash
bash -euo pipefail -c '
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d web worker-critical worker-default worker-bulk redis db
'
```
判定规则:`bootstrap` 非 0 立即终止,且不得执行任何 `up web/worker-*`
### 12.3 容器运行(compose
说明:以下用于本地联调/排障;发布流程仍以 `runtime-bootstrap-gate` 作为唯一放行依据。
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d web worker-critical worker-default worker-bulk redis db
docker compose --env-file .env -f infra/docker/docker-compose.yml ps
```
### 12.4 CI 流程(pipeline
```bash
bash -euo pipefail -c '
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm init-job bootstrap
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d web worker-critical worker-default worker-bulk redis db
'
PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/runtime/test_cli.py backend/tests/unit/test_process_settings.py -q
PYTHONPATH=backend/src uv run pytest backend/tests/integration -q
PYTHONPATH=backend/src uv run pytest backend/tests/e2e/test_infra_health_e2e.py -q
```
CI 要求:上述 gate step 名称固定为 `runtime-bootstrap-gate`,不得拆分为两个可独立重试的 step。
## 13. 队列拆分后的观测与告警基线
| 指标 | 目标阈值 | 告警条件 | 处置建议 |
|---|---|---|---|
| `queue_depth{queue=critical}` | P95 < 20 | 连续 5 分钟 >= 50 | 提升 critical 并发或排查阻塞任务 |
| `task_latency_seconds{queue=critical}` | P95 < 3s | 连续 10 分钟 P95 >= 8s | 检查路由漂移与上游突发 |
| `task_latency_seconds{queue=default}` | P95 < 30s | 连续 10 分钟 P95 >= 90s | 扩容 default 或拆分热点任务 |
| `task_failure_rate{queue=*}` | < 2% | 5 分钟窗口 >= 5% | 触发失败任务抽样与回滚评估 |
| `worker_process_alive{group=*}` | 全部存活 | 任一 group 存活实例 < 1 持续 2 分钟 | 自动重启并标记发布风险 |
| `worker_cpu_usage{group=*}` | < 80% | 连续 10 分钟 >= 90% | 下调并发或扩容容器配额 |
说明:至少落地前 5 个指标;第 6 个为推荐增强项。
## 14. 回滚演练用例(新入口 -> legacy
### 14.0 前置资产与留档要求(硬前置)
- 资产清单:Compose `--profile legacy` 下必须存在并可执行 `bootstrap-legacy``web-legacy``worker-legacy`
- 留档位置:`docs/runtime/rollback-drills/`,文件命名 `YYYY-MM-DD-runtime-legacy-drill.md`
- 留档最小字段:版本号、镜像 digest、执行命令、开始/结束时间、关键日志路径、通过判定、遗留问题。
- 关卡规则:**Phase 1 完成后必须执行一次并留档;未留档不得进入 Phase 2/3/4/5。**
### 14.1 演练触发场景
- `init-job bootstrap` 成功但 `web/worker` 启动后出现持续错误率超阈值。
- 队列延迟超过第 13 节阈值且 30 分钟内无法恢复。
### 14.2 演练步骤
1. 记录当前版本号、镜像 digest、配置快照。
2. 停止新入口服务:`docker compose --env-file .env -f infra/docker/docker-compose.yml stop web worker-critical worker-default worker-bulk`
3. 启动 legacy 入口(deprecate profile):`docker compose --env-file .env -f infra/docker/docker-compose.yml --profile legacy run --rm bootstrap-legacy && docker compose --env-file .env -f infra/docker/docker-compose.yml --profile legacy up -d web-legacy worker-legacy redis db`
4. 执行健康检查与关键任务回归(必须执行以下命令):
```bash
# 健康探测(5 连续成功)
for i in 1 2 3 4 5; do
curl -fsS http://127.0.0.1:8000/health >/dev/null || exit 1
done
# 关键路由回归(critical/default/unknown fallback
PYTHONPATH=backend/src uv run pytest \
backend/tests/integration/test_celery_routing.py::test_route_critical_task_to_critical_queue \
backend/tests/integration/test_celery_routing.py::test_route_default_task_to_default_queue \
backend/tests/integration/test_celery_routing.py::test_route_unknown_task_to_default_with_warning -q
# 基础链路回归
PYTHONPATH=backend/src uv run pytest backend/tests/e2e/test_infra_health_e2e.py -q
# legacy worker 告警与关键链路日志检索
docker compose --env-file .env -f infra/docker/docker-compose.yml --profile legacy logs worker-legacy --since=10m | rg "critical|celery.route.fallback"
```
5. 对比回滚前后 30 分钟指标(错误率、队列深度、延迟)。
### 14.3 通过判定
- `web-legacy``worker-legacy` 在 10 分钟内恢复服务。
- `/health` 连续 5 次探测通过(上方循环命令 exit code = 0)。
- 关键回归命令全部通过:三条 routing 集成测试 + `test_infra_health_e2e.py` 均 exit code = 0。
- `critical` 任务链路恢复,失败率回落至 < 2%,且 `worker-legacy` 日志 10 分钟窗口内至少出现 1 条 `critical` 命中记录。
- 演练记录文档已提交到 `docs/runtime/rollback-drills/` 且可被 CI/评审引用。
## 15. Worker 并发基线压测与调参回归
### 15.1 基线压测
- 压测对象:`worker-critical/default/bulk` 三组并发参数(`concurrency/prefetch_multiplier/max_tasks_per_child`)。
- 压测数据:至少包含短任务(<1s)、中任务(1~10s)、长任务(>10s)三类。
- 产出:每组生成吞吐、P95 时延、失败率、CPU/内存曲线基线报告。
### 15.2 调参流程
1. 固定流量模型,单次仅调整一个参数。
2. 每轮调参后运行 30 分钟压测并记录指标。
3. 若任一关键指标恶化超过 10%,回退上一组参数。
4. 选择满足 SLA 且资源利用率最优的一组作为默认值。
### 15.3 回归要求
- 每次 worker 参数变更必须复跑第 1.4.1 的全部可测门槛。
- 必跑回归:`test_cli.py``test_process_settings.py``test_infra_health_e2e.py`
- 覆盖率不得低于 80%。
## 16. 文档级 Go 判定(可执行)
| 判定项 | 必跑命令 | Go 门槛 |
|---|---|---|
| 门禁一致性(禁止绕过) | `rg -n "runtime-bootstrap-gate|needs:\s*\[?runtime-bootstrap-gate\]?" .github/workflows && rg -n "docker compose .*up -d .*\b(web|worker-critical|worker-default|worker-bulk)\b" .github/workflows` | 第一条命中 >= 2;第二条仅允许命中 gate 执行器文件;否则 No-Go |
| 文档闭环 | `rg -n "docker compose .* -f docker/docker-compose.yml" AGENTS.md docs/ infra/ backend/ ; rg -n "docker compose .* --env-file .env -f infra/docker/docker-compose.yml" AGENTS.md backend/AGENTS.md docs/runtime/runtime-runbook.md .env.example` | 前者无输出;后者命中 >= 4 |
| 路由策略一致性 | `PYTHONPATH=backend/src uv run pytest backend/tests/integration/test_celery_routing.py::test_route_critical_task_to_critical_queue backend/tests/integration/test_celery_routing.py::test_route_default_task_to_default_queue backend/tests/integration/test_celery_routing.py::test_route_unknown_task_to_default_with_warning -q` | 3/3 用例通过,且 unknown 路由回落 default 并有告警 |
| 关键任务链路恢复(回滚场景) | `for i in 1 2 3 4 5; do curl -fsS http://127.0.0.1:8000/health >/dev/null || exit 1; done && PYTHONPATH=backend/src uv run pytest backend/tests/e2e/test_infra_health_e2e.py -q` | 健康探测 5/5 成功且 E2E 通过 |
| 质量门槛 | `PYTHONPATH=backend/src uv run pytest backend/tests/unit backend/tests/integration --cov=backend/src --cov-report=term-missing --cov-fail-under=80` | 覆盖率 >= 80%exit code = 0 |
执行规则:以上 5 项全部满足才可判定文档级 Go;任一项不满足即回退 `In Review`