fix(controller,worker): dual-state worker loss + resend actual job state (bug-1509 P3)
Phase 3 (B1 dual-state + B2): a job never lingers as RUN when its worker is lost. Dual-state B1 (user-approved): RDHUP (worker TCP dropped = confirmed dead) marks its RUN jobs EXIT immediately (mark_worker_jobs_exit). Heartbeat timeout (unknown) keeps them UNKWN+TRANSIENT awaiting reconnect reconciliation; the TRANSIENT TTL GC is the backstop. handle_worker_leave now calls mark_worker_jobs_exit (was mark_worker_jobs_unknown in Phase 2). B2 (worker side): resend_job_status now checks the recovered process is alive (kill(pid,0)) before re-reporting RUN — a dead process is reported finished so the controller converges to EXIT instead of a stale RUN. And resend_job_status runs on EVERY rejoin (checking_connection), not just startup, so a reconnecting worker's jobs are reconciled (clears UNKWN via the existing notify_jobstart claim path). Design: docs/Job-Finish-Robustness-设计文档.md §4.4 (dual-state decision). Unit test: worker RDHUP marks jobs EXIT (not UNKWN).
This commit is contained in:
parent
fc091348e8
commit
d3a92f1033
7 changed files with 135 additions and 18 deletions
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
| ID | 严重度 | 问题 | 修订 |
|
||||
|----|--------|------|------|
|
||||
| **B1** | HIGH | grace 窗口把"仅分区"(TCP half-open,作业仍在跑)的 worker 的作业 EXIT;终态后 worker 的 RUNNING 认领被 `job_state_is_backward` 拒绝 → 孤儿进程 + 永久错误终态。 | 🔧 §4.4:grace 放宽/可配;区分"确认死亡"vs"未知";加 EXIT 后核对(worker 认领则复活或杀孤儿) |
|
||||
| **B1** | HIGH | grace 窗口把"仅分区"(TCP half-open,作业仍在跑)的 worker 的作业 EXIT;终态后 worker 的 RUNNING 认领被 `job_state_is_backward` 拒绝 → 孤儿进程 + 永久错误终态。 | ✅ 已定双态(§4.4):RDHUP(确认死亡)→ 立即 EXIT;心跳超时(未知)→ UNKWN 等重连核对,不 EXIT(TRANSIENT TTL 兜底)。孤儿风险已接受 |
|
||||
| **A3** | MED/HIGH | unknown 注册表进程内、不跨 failover:primary 登记 finish 后 failover,新 primary 重放 submit(PEND)但 finish 丢失 → PEND 永久卡住(B3 只覆盖 RUN)。 | 🔧 §3.6:Phase 1 文档化为残留风险;后续持久化 deferred finish 或把 B3/B4 扩展到 PEND |
|
||||
| **B4** | MED | sqlite 不存 exit code,resend 硬编码 exit_code=0;存的 pid 是 xcecd-worker 子进程(非作业命令树);MPI/多进程作业需 pgid 级存活。 | 🔧 §4.2:上报前从 systemd unit 状态 / reaped wait status 推导 exit code;用存储的 job_status 作提示 |
|
||||
|
||||
|
|
@ -172,14 +172,17 @@ START/FAIL/STOP/RESUME 等 worker 事实通知存在同样的"作业未实体化
|
|||
- `persist_recover` 回放完成后,把所有 **RUN 状态**的作业置 `JOB_STAT_UNKWN` + `JOB_STAT_TRANSIENT` + `transient_since = now`(重启后与 worker 连通性未知)。
|
||||
- 解决"重启后 RUN 作业(无 allocs)永远卡住"的问题;后续由 B4 重连核对收敛。
|
||||
|
||||
### 4.4 B4:重连核对(worker 上报 → controller 交叉核对)
|
||||
### 4.4 B4:重连核对(worker 上报 → controller 交叉核对)【已定双态】
|
||||
|
||||
- worker(重)join 后,修复后的 `resend_job_status` 上报其运行 jobid 清单。
|
||||
- controller 收到上报后:
|
||||
- 被上报的作业(UNKWN 态)→ 清 UNKWN/TRANSIENT → 保持 RUN(确认存活)。
|
||||
- 过了 **grace 窗口**(建议 60s,等所有 worker 重连)仍未被任何 worker 认领的 UNKWN 作业 → `mark_job_fail`(EXIT)。
|
||||
- worker-push 模型无需 exec-host 映射:worker 自己报运行作业,controller 交叉核对。
|
||||
- 🔧 **B1(grace 误杀防护)**:grace 窗口内把"仅分区"(TCP half-open、作业仍在跑)的 worker 的作业 EXIT 会**留下孤儿进程**——终态后 worker 的 RUNNING 认领被 `job_state_is_backward` 拒绝(job.c:43-46,record_job_start_fact job.c:1590)。措施:grace 放宽/可配(建议 ≥ 数个存活超时周期);区分"worker 确认死亡"vs"状态未知";加 EXIT 后核对——worker 后来认领则复活作业或杀孤儿。
|
||||
**双态决策(2026-08-06,用户确认方案 3)**:
|
||||
- **RDHUP(TCP 断开,确认死亡)** → `mark_worker_jobs_exit`:该 worker 的 RUN 作业**立即置 EXIT**(终态,finish_time/exit_info 设置)。不等待核对。
|
||||
- **心跳超时(未知)** → `mark_worker_jobs_unknown`:RUN 作业置 `UNKWN+TRANSIENT`,**等重连核对,不 EXIT**;worker 永不回来则由 TRANSIENT TTL(`transient_job_timeout_s` 默认 300s)GC 兜底。
|
||||
- **认领路径(已天然工作)**:worker(重)连上报运行作业(`notify_jobstart`)→ WAL_JOB_START apply → `apply_job_update_transition` 设 state=RUN,**自动清除 UNKWN/TRANSIENT**。
|
||||
|
||||
worker 侧重连上报(B2):
|
||||
- `resend_job_status` **每次 join/rejoin 都调用**(不只启动),上报运行作业清单。
|
||||
- 上报前用 `kill(pid,0)` 查进程实际状态:活着 → 报 RUN;已死 → 报 finish(EXIT),不再盲目报 RUN。
|
||||
- 🔧 B1 已按上述双态解决(不再有"grace 窗口误杀"——未知态不 EXIT)。遗留孤儿风险(RDHUP→EXIT 但 worker 侧 systemd unit 可能仍在跑):终态后 worker 认领被 `job_state_is_backward` 拒绝(job.c:43-46),孤儿进程最终自行结束或由后续清理。已接受(用户决策)。
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue