feat: 长任务补齐——流式进度 + 跨进程中断 + worker 超时约定

- 长等待流式进度:run_turn 改 1 秒切片轮询(_wait_turn),每满 --progress-interval(默认 30 秒,0 关闭,CLI > 配置 > 默认)往 stderr 打 turn progress 并往链路文件记 kind=progress;进度绝不走 stdout,不破坏 dispatch JSON 与 goal 结论行/用量行解析(经 cloud 真正则验过)
- 跨进程中断:interrupt 直接不生效时写 <state_dir>/interrupt-requests/<task>.json,属主等 turn 时每秒轮询到后用自己的 live 连接发 turn/interrupt 并记 interrupted;10 秒内未响应也不删文件,属主下次轮询仍处理;接线覆盖 dispatch/run/goal/goal-resume/delegate/parallel/fix-review/run-due;旧 server 不接受 interrupt_file 时退回不传再跑
- cloud worker 超时约定:--task-timeout 0 归一化为 None(不限时,与 host turn_timeout 同约定,Docker 路径仍受 docker_timeout 约束),默认 1800 不变;超时仍记 failed(现有单测合同不动)

测试:host 56 全过(新增 7)、cloud 526 全过(4 跳过,新增 1 个 0=不限时)。
This commit is contained in:
host committed 2026-10-27 03:05:15 +08:00
1 parent 028ef02a86
commit 1128fd3076
6 files changed
+400 -34

No files matched your search

+20 -4
View File
@@ -68,6 +68,12 @@ interrupted,不用执行结果覆盖它。
runner / 无超时的 subprocess.run)无法在中途抢占一个已阻塞
的调用,超时只能靠执行器自身的 timeout,这是诚实边界,
不要假装同步路径也能中途杀掉。
- 对齐 host.py 的 turn_timeout 约定:task_timeout 传 0 时
归一化为 None(不限时,worker 级不设截止),与 host 的
“0 = 不限时”同约定;默认 1800 不变,不改默认就不会悄悄
挂起自动化。worker 级不限时时,Docker 路径仍受执行器
docker_timeout 约束(timeout=None 时 _call_runner 用
executor 自身的 timeout),不是全链路无限。
- max_retries(默认 1 次重试,CLI --max-retries 可调,0 表示
不重试)是对模型任务失败的有限重试:取消不重试;可 fallback
的失败优先走真实 fallback(见下),不再做同模型重试(fallback
@@ -311,6 +317,14 @@ class Worker:
self._loop_stop = False
self.logger = get_logger("cloud.worker")
# 任务级超时 / 失败重试(见模块 docstring 的生产级说明)。
# 对齐 host turn_timeout:0 归一化为 None(不限时),
# 负数同理;默认 1800 不变。归一化后 _run_attempt 里
# task_timeout is None 的分支本来就走“无 worker 级截止”
#(Docker 路径仍受 executor docker_timeout 约束),
# 不用再改各执行路径;不归一化的话 0 会在 popen 轮询
# 里第一轮就触发“已到截止时间”而立即超时,是反直觉的 bug。
if task_timeout is not None and task_timeout <= 0:
task_timeout = None
self.task_timeout = task_timeout
self.max_retries = max_retries
self.retry_backoff_seconds = retry_backoff_seconds
@@ -2102,10 +2116,12 @@ def main(argv=None):
" worker 必须开,否则它会抢走本该进"
" Docker 容器的 NULL 任务")
parser.add_argument("--task-timeout", type=float, default=1800,
help="每任务截止时间(秒,默认 1800);超时后真杀"
"容器/进程组、任务置 failed;与 --docker-timeout"
"(单次 docker run 超时)取较小值,与"
" --max-seconds(run_loop 整体墙钟上限)不同")
help="每任务截止时间(秒,默认 1800);0 表示不限时"
"(与 host --turn-timeout 0 同约定,worker 级"
"不设截止,但 Docker 路径仍受 --docker-timeout"
"约束);超时后真杀容器/进程组、任务置 failed;"
"与 --docker-timeout(单次 docker run 超时)取"
"较小值,与 --max-seconds(run_loop 整体墙钟上限)不同")
parser.add_argument("--max-retries", type=int, default=1,
help="模型任务失败重试次数(默认 1,0 表示不重试;"
"取消与已记 fallback 的失败不重试)")