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

+21
View File
@@ -123,6 +123,27 @@ class WorkerTimeoutTestCase(unittest.TestCase):
self.assertIn("worker_timeout", _audit_actions(db_path))
tmp.cleanup()
def test_task_timeout_zero_means_unlimited(self):
# 对齐 host turn_timeout:0 归一化为 None(不限时),
# 而不是在 popen 轮询第一轮就立即超时。sleep 0.5 的
# 任务在 task_timeout=0 下应正常完成,库里是 completed。
tmp = tempfile.TemporaryDirectory()
def factory(task):
return subprocess.Popen(
["sleep", "0.5"], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, text=True, start_new_session=True)
worker, db_path, task = _make_worker(
tmp.name, process_factory=factory, task_timeout=0,
max_retries=0, retry_backoff_seconds=0)
self.assertIsNone(worker.task_timeout)
result = worker.run_one(task)
self.assertEqual(result["status"], "completed")
status, _ = _task_row(db_path)
self.assertEqual(status, "completed")
tmp.cleanup()
def test_docker_timeout_converts_to_failed_and_audit(self):
tmp = tempfile.TemporaryDirectory()