## 背景 2026-10-15 21:38 手动部署替换容器,打断了 21:33 提交的转写任务(task_ed2316…,被启动孤儿恢复标 failed,错误信息 Task interrupted by service restart)。任务队列在内存中,进程替换即丢失。 ## 已落地(PR #246) - D3 自动部署接入(push main 自动部署 + workflow_dispatch 手动补发) - 部署侧忙锁参数已启用:busy_lock_file=/opt/media/VideoTranscriptAPI/.deploy-state/busy.lock,timeout 600s - 服务侧 BusyLock + compose 挂载(本 PR 第四轮) - 事前 pre-flight + 事后 verify-busy-lock-inode 双闸(本 PR 第六轮 / gate primary 第 4 轮):替换前对当前运行容器做 inode 对账,失败则 ship 不跑 ## 修复计划(本 issue 的收口判据) 服务侧忙锁(卡 VideoTranscriptAPI-20261015-02)已在 PR #246 落地: - BusyLock 模块:转写任务受理→终态全程持 LOCK_SH(非阻塞 admission,拿不到返回 503) - 终态路径(成功/失败收口)释放 - compose 部署种子加 ./.deploy-state:/app/.deploy-state 挂载 - 跨进程真实 flock 测试(部署侧 LOCK_EX 持有时 admission 必须拒绝;终态后必须放行) 服务侧合并且**第二次及以后**的 D3 自动部署:有在飞任务时 defer(exit 3,旧容器保留);无挂载/inode 不一致时 pre-flight 失败、ship 不执行。本 issue 在首次人工容器重建完成、pre-flight 已在一次自动部署中通过后可关。 ## 首次容器重建(不走 deploy.yml) 旧容器没有 `.deploy-state` 挂载,pre-flight 对它会失败——这是设计(fail-closed),不是要绕过的闸。 合并后由主脑 ssh 在部署目录执行 `docker compose up -d` 做**第一次**容器重建(把 compose 换成带挂载的种子),**不要**走 deploy.yml / workflow_dispatch。步骤: 1. 确认非终态任务为 0:`sqlite3 data/cache/cache.db 'select count(*) from task_status where status not in ("success","failed")'` 为 0 2. 确认部署目录 compose 已是本仓种子形态(含 `./.deploy-state:/app/.deploy-state`) 3. `docker compose up -d` 4. 确认宿主 `.deploy-state/busy.lock` 存在(没有则 touch),且容器内 `/app/.deploy-state/busy.lock` 与宿主 `stat -c %i` 一致 此后自动路径的 pre-flight 才会通过。 ## 过渡期缓解(首次重建完成前) - 不要用 push main / workflow_dispatch 触发 deploy.yml(pre-flight 会对旧容器失败,ship 不会跑) - 部署前人工确认无非终态任务 - 尽量避开业务高峰 Refs: PR #246, gate run 38770699923
Activity
zj1123581321 commentedon Oct 15, 2026
顾问裁决补充(consult 20261016-012652-codex):服务侧忙锁改为并入 PR #246 同分支续做(原独立卡取消)。新增一条过渡期不变式:PR 合并后的首次自动部署发生在旧容器(无持锁代码)运行时,忙锁保护生效前存在空档——首次部署前必须人工确认无非终态任务为 0;之后的部署由忙锁自动 defer。
zj1123581321 commentedon Oct 15, 2026
gate primary 第 4 轮语义更新(PR #246 第六轮):
docker compose up -d(先确认非终态任务为 0)。pre-flight 从第二次自动部署起自然通过。zj1123581321 commentedon Oct 15, 2026
第 6 轮(gate 第 5 轮 findings 修复)语义变化:服务侧 BusyLock 从 fail-open 改为 fail-closed——锁基础设施异常(挂载/权限/flock 故障)时拒绝新任务(503),不再放行。影响窗口:PR #246 合并后到首次人工部署之间,新任务会被拒(窗口分钟级,主脑控制);首次部署完成后窗口消失。已接任务不受影响(锁已持有,跑完到终态正常释放)。
zj1123581321 commentedon Oct 15, 2026
首次人工部署操作步骤更新(服务侧禁自建锁文件契约):
docker compose up -d前必须先预建锁文件:mkdir -p /opt/media/VideoTranscriptAPI/.deploy-state && touch /opt/media/VideoTranscriptAPI/.deploy-state/busy.lock。不预建的后果:服务侧 ENOENT → 全部新任务 503(fail-closed 按设计工作,但服务不可用)。首次部署 verify 通过后会自动写入 .deploy-state/last_verified_good(回滚锚点);若首次部署 verify 即失败报 rollback_failed 属预期 fail-loud,按 DEPLOY.md 灾备兜底。zj1123581321 commentedon Oct 16, 2026
进度:PR #246 已带闸合并(merge commit 6080131,主脑获用户授权)。首次人工部署完成:.deploy-state/busy.lock 预建、容器带挂载重建、inode 对账一致(host=container=1840832)、/livez ok、公网入口 200。剩余:等待 deploy workflow 排队(fleet 同 host 部署槽串行)自动部署含 BusyLock 的新代码——届时 pre-flight/verify 全链首次实弹运行,本 issue 的忙锁闭环以该次部署成功为收官判据。