Merge pull request #157 from openqj/feat-final-audit-detail

fix(worker): 终态审计带上 error,复发卡死可定位
This commit is contained in:
openqj authored and GitHub committed 2026-10-30 01:53:39 +08:00
commit aa5bf7da72
2 files changed
+36 -1

No files matched your search

+25
View File
@@ -481,6 +481,31 @@ class WorkerTestCase(unittest.TestCase):
self.assertEqual(result["status"], "interrupted")
self.assertEqual(_status(self.db_path, "A"), "interrupted")
def test_final_audit_detail_carries_error(self):
# 2026-10-29 任务 A 教训:终态审计只记 task_id 时,
# interrupted/failed 的原因事后无法区分,且自动续跑
# 会把 error_text 覆盖掉。非完成终态的审计 detail
# 必须带上 error,完成态仍只记 task_id。
_insert_task(self.db_path, "A")
def failing(cmd):
return SimpleNamespace(returncode=1, stdout="",
stderr="dispatch boom xyz")
worker = self._worker(runner=failing)
result = worker.run_one()
self.assertEqual(result["status"], "failed")
from cloud.auth import AuthStore
store = AuthStore(self.db_path)
try:
entries = [e for e in store.list_audit("p1")
if e["action"] == "worker_failed"]
finally:
store.conn.close()
self.assertTrue(entries)
self.assertTrue(entries[0]["detail"].startswith("A:"))
self.assertIn("boom", entries[0]["detail"])
# -- 缺 key 门 --------------------------------------------------------
def test_missing_key_fails_clearly_and_does_not_run(self):
_insert_task(self.db_path, "A")
+11 -1
View File
@@ -5167,12 +5167,22 @@ class Worker:
if final_written:
# 审计名须与终态一致:interrupted 任务记 worker_failed
# 会把“可续跑的中断”误读成失败,误导后续排查。
# 终态审计细节(2026-10-29 任务 A 教训):interrupted /
# failed 时只记 task_id,事后完全无法区分是取消、
# 配额、host 返回 interrupted 还是其它失败——且自动
# 续跑会把 error_text 覆盖掉,第一轮的原因就此丢失。
# 因此非完成终态的审计 detail 带上 error(截 500 字、
# 去换行,不含 prompt/key),完成态仍只记 task_id。
_final_detail = task_id
if final in ("interrupted", "failed") and error:
_final_detail = "%s: %s" % (
task_id, str(error)[:500].replace("\n", " "))
self._audit(task["project_id"],
"worker_quota_stop" if quota_stop else
("worker_completed" if final == "completed"
else "worker_interrupted"
if final == "interrupted"
else "worker_failed"), task_id)
else "worker_failed"), _final_detail)
log_event(self.logger,
"worker_quota_stop" if quota_stop else
("worker_completed" if final == "completed"