Files
social-app/docs/runtime/runtime-runbook.md
T

276 lines
9.7 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 Runbook
**Date:** 2026-02-25
**Status:** Active
**Audience:** 运维 / 后端值班
## Scope & Preconditions
本手册用于日常值班、发布前检查、故障处置与回滚。
### 前置条件
- 已配置 `.env`(仓库根目录)。
- 主机可用:`docker``docker compose``tmux``uv`
- 已拉取最新代码并确认当前分支与目标发布版本一致。
### 红线规则
- 禁止跳过 bootstrap gate 直接启动 web/worker。
- 迁移/初始化容器执行时必须带 `--build`,避免旧镜像导致迁移不生效。
---
## Bootstrap Gate (Mandatory)
以下流程必须按顺序执行。
### Step 1: 启动基础设施
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d
```
通过标准:`docker compose ... ps` 中 redis/supabase 相关容器为 `running`
### Step 2: 执行迁移与初始化
#### 生产环境
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml run --rm --build init-job uv run python -m core.runtime.cli bootstrap
```
#### 开发环境(推荐)
开发阶段推荐使用脚本,直接使用本地代码,无需构建镜像:
```bash
bash infra/scripts/dev-migrate.sh bootstrap
```
可选命令:
- `bash infra/scripts/dev-migrate.sh migrate` - 仅运行迁移
- `bash infra/scripts/dev-migrate.sh init-data` - 仅初始化数据
通过标准:命令退出码为 0,日志中无 migration/init-data 错误。
### Step 3: 版本核对(建议)
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml exec -T db \
psql -U postgres -d postgres -c "SELECT version_num FROM public.alembic_version;"
```
通过标准:返回 1 行版本号,且与发布预期版本一致。
---
## Service Start / Stop (tmux)
### 启动应用进程
```bash
bash infra/scripts/app.sh start
```
该脚本会在 tmux `social-dev` 会话中拉起:
- web
- worker-critical
- worker-default
- worker-bulk
通过标准:`tmux list-windows -t social-dev` 可见上述窗口。
### 常用 tmux 命令
```bash
tmux list-windows -t social-dev
tmux attach -t social-dev
tmux kill-session -t social-dev
```
### 日志文件
| 服务 | 日志文件 |
|------|---------|
| Web | `logs/web.log`, `logs/errors/web.error.log` |
| Worker Critical | `logs/worker-critical.log`, `logs/errors/worker-critical.error.log` |
| Worker Default | `logs/worker-default.log`, `logs/errors/worker-default.error.log` |
| Worker Bulk | `logs/worker-bulk.log`, `logs/errors/worker-bulk.error.log` |
---
## Operational Verification
按优先级分层执行。
### L1 必跑(发布前/故障恢复后必须)
```bash
# 先导入 .env,确保端口与配置一致
set -a
. ./.env
set +a
WEB_BASE_URL="http://127.0.0.1:${SOCIAL_WEB__PORT:-5775}"
# 基础健康
curl -fsS http://127.0.0.1:${SOCIAL_SUPABASE__KONG_HTTP_PORT:-8000}/health
# compose 状态
docker compose --env-file .env -f infra/docker/docker-compose.yml ps
# 核心接口 smoke
curl -sS -X POST "${WEB_BASE_URL}/api/v1/auth/login" \
-H 'Content-Type: application/json' \
-d '{"email":"demo@example.com","password":"secret123"}'
```
通过标准:health 返回 2xx,关键容器 `running`,核心接口返回预期业务状态码。
### L2 可选(Auth/Profile 业务回归)
```bash
# signup start
curl -sS -X POST "${WEB_BASE_URL}/api/v1/auth/verifications" \
-H 'Content-Type: application/json' \
-d '{"username":"demo","email":"demo@example.com","password":"secret123"}'
# signup verify
curl -sS -X POST "${WEB_BASE_URL}/api/v1/auth/verifications/verify" \
-H 'Content-Type: application/json' \
-d '{"email":"demo@example.com","token":"123456"}'
# signup resend
curl -sS -X POST "${WEB_BASE_URL}/api/v1/auth/verifications/resend" \
-H 'Content-Type: application/json' \
-d '{"email":"demo@example.com"}'
# profile patch
curl -sS -X PATCH "${WEB_BASE_URL}/api/v1/profile/me" \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer <access_token>" \
-d '{"username":"demo2","bio":"hello"}'
# profile get
curl -sS "${WEB_BASE_URL}/api/v1/profile/me" \
-H "Authorization: Bearer <access_token>"
```
通过标准:接口返回符合预期的 2xx 或受控业务错误,无 5xx。
## Incident Playbook
### 1) 迁移未生效(常见于旧镜像)
- 症状:字段/表结构与代码不一致,接口报 schema 错误。
- 定位:检查 `alembic_version` 与容器镜像构建时间。
- 修复:重新执行 `init-job --build`,并复核版本号。
### 2) Worker 不消费任务
- 症状:队列堆积,任务长时间 pending。
- 定位:检查 `worker-*` tmux 窗口和对应日志文件。
- 修复:重启 tmux 会话,确认并发配置与队列名(critical/default/bulk)。
- 说明:Taskiq 路径当前仅消费 `SOCIAL_WORKER__GROUPS__*__CONCURRENCY`,旧 Celery 参数(prefetch/time_limit 等)已废弃。
### 2.1) Agent Runtime run/resume 事件不闭环
- 症状:`POST /api/v1/agent/runs` 返回 202,但前端事件流没有 `RUN_FINISHED`
- 定位步骤:
```bash
# 1) 检查 taskiq worker 是否消费 agent 任务
grep -E "tasks\.agent\.run_command|RUN_STARTED|RUN_FINISHED|RUN_ERROR" logs/worker-default.log
# 2) 检查 API SSE 事件读取(带 Last-Event-ID
curl -N "${WEB_BASE_URL}/api/v1/agent/runs/<session_id>/events" \
-H "Authorization: Bearer <access_token>" \
-H "Last-Event-ID: 1-0"
# 3) 检查 Redis 连通(必要时)
docker compose --env-file .env -f infra/docker/docker-compose.yml exec -T redis redis-cli ping
```
- 修复建议:
- 若 worker 无消费:重启 `worker-default` 窗口并确认 `core.agent.infrastructure.queue.tasks` 已被 Taskiq worker 加载。
- 若 worker 有事件但 API 无输出:排查 Redis stream 前缀配置与 session_id 是否一致。
- 若出现 `RUN_ERROR`:按 error_id 回查后端日志,不在 API/SSE 中暴露敏感上下文。
### 3) JWT 或认证异常
- 症状:接口持续 401/403。
- 定位:核对 `.env` 中 Supabase JWT 配置与签发方设置。
- 修复:修正配置后重启 web 进程并执行 L1/L2 验证。
### 4) Auth 邮件模板未生效 / 注册返回超时但邮件已发送
- 症状:
- 收到默认英文模板(非 `infra/mail-templates`)。
- `signup/start` 偶发 500 或超时,但邮箱仍收到验证码邮件。
- 根因:容器配置漂移(旧容器未按最新 compose/.env 重建),导致:
- `supabase-auth` 缺少 `GOTRUE_MAILER_TEMPLATES_*` 环境变量。
- `supabase-mail-templates` 仍挂载旧路径。
- 定位:
```bash
docker inspect supabase-auth --format '{{ range .Config.Env }}{{ println . }}{{ end }}' | grep GOTRUE_MAILER_TEMPLATES
docker inspect supabase-mail-templates --format '{{ range .Mounts }}{{ .Source }} -> {{ .Destination }}{{ println }}{{ end }}'
```
- 修复:强制重建 auth 和 mail-templates(不改其他服务):
```bash
docker compose --env-file .env -f infra/docker/docker-compose.yml up -d --force-recreate --no-deps mail-templates auth
```
- 复核标准:
- `docker inspect supabase-auth` 能看到 `GOTRUE_MAILER_TEMPLATES_CONFIRMATION/RECOVERY`
- `supabase-mail-templates` 挂载源为 `infra/mail-templates`
- `POST /api/v1/auth/verifications` 返回 `202` 且耗时恢复正常。
---
## Rollback Procedure
### 回滚前检查
- 确认目标回滚提交或版本号。
- 确认是否涉及不可逆数据变更。
### 回滚执行
1. 停止应用进程:`tmux kill-session -t social-dev`
2. 切换代码到目标版本。
3. 按目标版本要求执行迁移回滚(如有)。
4. 重新执行 bootstrap gate 与 service 启动。
### 回滚后复核
- 执行 L1 必跑检查。
- 记录回滚原因、时间、影响范围和后续修复计划。
---
## Change Log
| 日期 | 变更 |
|------|------|
| 2026-02-24 | 创建运行时手册,删除 legacy 脚本,统一使用 gunicorn |
| 2026-02-24 | 清理配置:合并 AppSettings 到 WebSettings,删除 Worker 旧配置 (enabled_queues/queues),统一使用 SOCIAL_WEB__GUNICORN__* 命名 |
| 2026-02-24 | 开发阶段 compose 暂不编排 web/worker,仅保留 redis/supabase 与 init-job |
| 2026-02-24 | 新增 dev-app-up 脚本:手动基础设施后,一键 bootstrap + tmux 拉起 web/worker |
| 2026-02-25 | 补充迁移防遗漏规则:容器迁移命令统一追加 --build;开发调试优先使用本地 CLI 一次性迁移脚本 |
| 2026-02-25 | Auth 注册切换为 OTP 三段式:signup/start、signup/verify、signup/resend;邮件模板改为纯验证码展示 |
| 2026-02-25 | 清理未使用配置类:删除 WebSettings/GunicornSettings/WorkerSettings/WorkerGroupSettings(脚本仍使用环境变量启动服务) |
| 2026-03-04 | Agent 运行时进入硬切重构:移除旧 Agent Chat 验证章节,待新方案落地后补充 |
| 2026-02-25 | 简化启动方式:dev-app-up -> app-up,分离 bootstrap 与服务启动 |
| 2026-02-25 | 重构为运维分层手册:Bootstrap Gate、分层验证、故障与回滚流程 |
| 2026-02-25 | 新增配置漂移故障条目:修复 Auth 邮件模板失效与 signup 超时场景 |
| 2026-02-27 | 用户搜索支持邮箱精确匹配:query 含 @ 符号时走 auth.users → profiles 两步查询 |
| 2026-02-28 | 邀请码功能:新增 invite_codes 表、profiles.referred_by,注册时可选填邀请码并记录邀请关系 |
| 2026-03-02 | 文档整理:修正 auth 端点名称(/verifications)、补充 profile 路由文档、修复 L2/L3 验证命令 |
| 2026-03-02 | 修正 bootstrap 命令:init-job 需要使用 `uv run python -m core.runtime.cli bootstrap` |
| 2026-03-05 | 新增 Agent Runtime run/resume/events 运维排障流程(Taskiq + Redis + Last-Event-ID |
| 2026-03-06 | Web 启动从 gunicorn 迁移为纯 uvicorn,移除 `SOCIAL_WEB__GUNICORN__*` 配置,统一使用 `SOCIAL_WEB__WORKERS` |