补齐API启动controller弱依赖
API systemd unit 增加 controller 弱依赖 生产 ops 护栏校验 API unit 依赖 同步运维文档和项目记忆说明
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
[Unit]
|
||||
Description=Genarrative Rust API Server
|
||||
After=network-online.target spacetimedb.service
|
||||
Wants=network-online.target
|
||||
Wants=network-online.target genarrative-external-generation-controller.service
|
||||
Requires=spacetimedb.service
|
||||
|
||||
[Service]
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
|
||||
- 现象:拼图首关生成接口返回 `queued`,但生成页长时间不完成,重启 `genarrative-api.service` 也没有推进任务。
|
||||
- 原因:HTTP 角色只入队,不再直接调用外部 provider;如果没有运行 `GENARRATIVE_PROCESS_ROLE=external-generation-worker` 或 `all` 的进程,`external_generation_job` 会停留在 `pending/running`,直到有 worker claim。
|
||||
- 处理:生产用 `systemctl enable --now genarrative-external-generation-worker@1.service genarrative-external-generation-controller.service` 启动保底 worker 和 controller;首次 API deploy 会在默认 worker pattern 下自动启用并启动 `@1`、等待 worker active,并重启验活 controller。扩容默认交给 controller 按队列统计启动 `@2.service` 等实例,手动扩缩容只作为兜底;worker 收到停机信号后会停止 claim 新任务并等待当前任务完成。本地 smoke 可临时用 `GENARRATIVE_PROCESS_ROLE=all npm run dev`;本地若只想同步排查可通过 `.env.local` 或本机环境设置 `GENARRATIVE_EXTERNAL_GENERATION_MODE=inline`,但这不会创建 job,也不能验证 worker 扩缩容。
|
||||
- 处理:生产用 `systemctl enable --now genarrative-external-generation-worker@1.service genarrative-external-generation-controller.service` 启动保底 worker 和 controller;`genarrative-api.service` 对 controller 使用 systemd `Wants` 弱依赖,启动 API 时会尝试一并拉起 controller,但不会让 HTTP 进程自己执行 `systemctl`。首次 API deploy 会在默认 worker pattern 下自动启用并启动 `@1`、等待 worker active,并重启验活 controller。扩容默认交给 controller 按队列统计启动 `@2.service` 等实例,手动扩缩容只作为兜底;worker 收到停机信号后会停止 claim 新任务并等待当前任务完成。本地 smoke 可临时用 `GENARRATIVE_PROCESS_ROLE=all npm run dev`;本地若只想同步排查可通过 `.env.local` 或本机环境设置 `GENARRATIVE_EXTERNAL_GENERATION_MODE=inline`,但这不会创建 job,也不能验证 worker 扩缩容。
|
||||
- 验证:`systemctl status genarrative-external-generation-controller.service 'genarrative-external-generation-worker@*.service'` 能看到 controller 和 worker 实例;queue 模式下任务被 claim 后 `worker_id` 与 `lease_expires_at` 会更新,完成后 session 进入 ready 或 failed;inline 模式下不应产生新的 `external_generation_job`。
|
||||
- 关联:`deploy/systemd/genarrative-external-generation-worker@.service`、`deploy/systemd/genarrative-external-generation-controller.service`、`deploy/env/external-generation-controller.env.example`、`server-rs/crates/spacetime-module/src/external_generation.rs`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
@@ -460,7 +460,7 @@
|
||||
|
||||
- 现象:release 机器 `03:20` 冷备份后,`spacetimedb.service` 已恢复,但作品列表、创作入口配置或公开 gallery 继续超时 / 502 / 504,`genarrative-api.service` 保持 stopped;或图片画布生成请求返回队列态后长期显示排队,`external_generation_job` 有 claimable pending,但 `genarrative-external-generation-worker@1.service` / controller 是 inactive。
|
||||
- 原因:`genarrative-api.service`、`genarrative-external-generation-worker@*.service` 和 `genarrative-external-generation-controller.service` 都配置了 `Requires=spacetimedb.service`,冷备份停止 `spacetimedb.service` 时这些服务会被 systemd 依赖关系一并停止;如果 `genarrative-database-backup.service` 只恢复数据库或只重启 API,外部生成队列就不会被消费。
|
||||
- 处理:生产冷备份 unit 和发布脚本必须带 `--restart-service-after genarrative-api.service`、`--restart-service-after genarrative-external-generation-worker@1.service` 和 `--restart-service-after genarrative-external-generation-controller.service`;仓库用 `npm run check:production-ops` 检查 systemd 模板、API build/deploy 归档和健康巡检链路。现场修复后执行 `systemctl daemon-reload`,但不要为了验证而手动触发冷备份。
|
||||
- 处理:生产冷备份 unit 和发布脚本必须带 `--restart-service-after genarrative-api.service`、`--restart-service-after genarrative-external-generation-worker@1.service` 和 `--restart-service-after genarrative-external-generation-controller.service`;`genarrative-api.service` 也保留对 controller 的 `Wants` 弱依赖,覆盖“只恢复 API”的现场兜底。仓库用 `npm run check:production-ops` 检查 systemd 模板、API build/deploy 归档和健康巡检链路。现场修复后执行 `systemctl daemon-reload`,但不要为了验证而手动触发冷备份。
|
||||
- 验证:`systemctl cat genarrative-database-backup.service` 应包含这些参数;`systemctl is-active spacetimedb.service genarrative-api.service genarrative-external-generation-worker@1.service genarrative-external-generation-controller.service nginx.service` 全为 `active`;`curl -fsS http://127.0.0.1:3101/v1/ping`、`/healthz`、`/readyz` 和代表性 `/api/runtime/puzzle/gallery` 均成功;`get_external_generation_queue_stats_and_return` 不应长期出现 claimable pending。
|
||||
- 关联:`deploy/systemd/genarrative-database-backup.service`、`scripts/database-backup-to-oss.mjs`、`scripts/ops/production-health-patrol.mjs`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ curl -f http://127.0.0.1:<api-port>/healthz
|
||||
|
||||
本地 `npm run dev` 与 `npm run dev:api-server` 默认注入 `GENARRATIVE_PROCESS_ROLE=all`,同一 Rust 进程同时监听 HTTP 并消费外部生成队列;显式设置 `GENARRATIVE_PROCESS_ROLE` 时保留显式值。需要验证生产式拆分角色、lease 重领或扩缩容时,再分别启动 `api`、`external-generation-worker` 和 `external-generation-controller`,也可以使用隔离容器 smoke。
|
||||
|
||||
生产 smoke 需要保持 `GENARRATIVE_EXTERNAL_GENERATION_MODE=queue`,并至少启动一个 `api` 角色、一个 `external-generation-worker` 角色和一个 `external-generation-controller` 角色;发布脚本会在默认 worker pattern 下自动启用并启动 `genarrative-external-generation-worker@1.service`,重启并验活 `genarrative-external-generation-controller.service`。若 worker 数量归零,生成任务会保持 `queued/running`,不会由 HTTP 进程偷偷执行。部署验证除 `/healthz` / `/readyz` 外,还要确认任务列表 BFF 可读、未确认终态任务会弹出提示、提示展示后后台 acknowledge 且刷新后不再弹出,单 job 状态能从 `queued/running` 收敛到业务 session/detail 的 ready 或 failed。
|
||||
生产 smoke 需要保持 `GENARRATIVE_EXTERNAL_GENERATION_MODE=queue`,并至少启动一个 `api` 角色、一个 `external-generation-worker` 角色和一个 `external-generation-controller` 角色;发布脚本会在默认 worker pattern 下自动启用并启动 `genarrative-external-generation-worker@1.service`,重启并验活 `genarrative-external-generation-controller.service`。`genarrative-api.service` 还通过 systemd `Wants=genarrative-external-generation-controller.service` 弱依赖覆盖只启动 API 的现场兜底;controller 仍是独立进程,不由 HTTP 进程内执行 `systemctl`。若 worker 数量归零,生成任务会保持 `queued/running`,不会由 HTTP 进程偷偷执行。部署验证除 `/healthz` / `/readyz` 外,还要确认任务列表 BFF 可读、未确认终态任务会弹出提示、提示展示后后台 acknowledge 且刷新后不再弹出,单 job 状态能从 `queued/running` 收敛到业务 session/detail 的 ready 或 failed。
|
||||
|
||||
systemd 生产 controller 与手动兜底示例:
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -18,6 +18,12 @@ const checks = [
|
||||
includes: '--restart-service-after genarrative-external-generation-controller.service',
|
||||
reason: '生产冷备份恢复 SpacetimeDB 后必须显式拉起外部生成 worker controller。',
|
||||
},
|
||||
{
|
||||
file: 'deploy/systemd/genarrative-api.service',
|
||||
includes: 'Wants=network-online.target genarrative-external-generation-controller.service',
|
||||
reason:
|
||||
'生产 API service 启动时必须弱依赖拉起外部生成 worker controller,避免只恢复 API 后队列无人消费。',
|
||||
},
|
||||
{
|
||||
file: 'deploy/systemd/genarrative-database-backup.service',
|
||||
includes: 'ExecStart=/usr/bin/node -- /opt/genarrative/current/scripts/database-backup-to-oss.mjs --env-file',
|
||||
|
||||
Reference in New Issue
Block a user