Files
codex-app-server/tests/test_host_resume_missing.py
host a5f2e4e091 fix: 断点丢失时 goal-resume 拒绝成 failed,阻断自动恢复空转
2026-10-29 长任务实弹:Docker goal 断点续跑在 host-state 里找
不到任务时抛 KeyError,worker 把无结论异常退出判 interrupted,
自动恢复再排队、再 KeyError,12 秒一轮空转 49 次(人工暂停
拦下,第 50 次人工续跑又烧掉),文件 32 章原样未动。
修法:host.py goal-resume 先查任务在不在 state 里,不在就打印
拒绝行、正常退出;sandbox 三处解析(本地、Docker resume、
Docker 断点)见拒绝行即判 failed 终态,不进自动恢复循环。
单测:host 缺任务拒绝不炸 + 三处解析拒绝判 failed。
2026-10-29 14:14:13 +08:00

67 lines
2.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""host.py goal-resume 断点丢失守卫:state 里没有任务时拒绝不炸。
2026-10-29 长任务实弹:断点续跑在 state 里找不到任务时抛
KeyError traceback,worker 把无结论异常退出判成 interrupted,
自动恢复再排队、再 KeyError,12 秒一轮空转到 50 次上限。
守卫后:打印拒绝行、正常返回,state 文件不动、线程不恢复。
"""
import io
import json
import os
import sys
import tempfile
import unittest
from contextlib import redirect_stdout
from pathlib import Path
from unittest import mock
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT))
import host
class FakeServer(object):
def __init__(self):
self.resumed = []
def initialize(self):
pass
def close(self):
pass
def resume_thread(self, thread_id):
self.resumed.append(thread_id)
class GoalResumeMissingTest(unittest.TestCase):
def test_missing_task_refuses_without_traceback(self):
with tempfile.TemporaryDirectory() as tmp:
state_path = os.path.join(tmp, "host-state.json")
cfg_path = os.path.join(tmp, "host-config.json")
with open(state_path, "w", encoding="utf-8") as f:
json.dump({"tasks": {"g": {"name": "g",
"thread_id": "x",
"status": "goal-running"}},
"automations": []}, f)
with open(cfg_path, "w", encoding="utf-8") as f:
json.dump({}, f)
fake = FakeServer()
argv = ["host.py", "--state", state_path,
"--config", cfg_path,
"goal-resume", "--task", "missing-task"]
out = io.StringIO()
with mock.patch.object(sys, "argv", argv):
with mock.patch.object(host, "Server",
lambda **kw: fake):
with redirect_stdout(out):
host.main()
self.assertIn("goal-resume 拒绝", out.getvalue())
self.assertIn("missing-task", out.getvalue())
self.assertEqual(fake.resumed, [])
with open(state_path, encoding="utf-8") as f:
saved = json.load(f)
self.assertEqual(list(saved["tasks"].keys()), ["g"])