83 lines
2.9 KiB
Python
83 lines
2.9 KiB
Python
"""
|
|
分层重试 — 部署在 orchestrator 调用者层(main.py / worker.py)。
|
|
"""
|
|
import logging
|
|
import os
|
|
from typing import Callable
|
|
from data.diff_result import VerificationRun
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
HEALING_FIXES = {
|
|
"compile_error": {
|
|
"detect": lambda log: "not found" in (log or "").lower(),
|
|
"fix": lambda: _try_set_env(
|
|
"COB_LIBRARY_PATH",
|
|
"D:\\360安全浏览器下载\\GC32-BDB-SP1-rename-7z-to-exe\\lib\\gnucobol",
|
|
),
|
|
},
|
|
"s0c7": {
|
|
"detect": lambda log: "S0C7" in (log or ""),
|
|
"fix": lambda: logger.warning("[Retry] S0C7 需要人工修正测试数据中的数值字段"),
|
|
},
|
|
}
|
|
|
|
|
|
def _try_set_env(key: str, value: str) -> None:
|
|
"""尝试设置环境变量(如果当前未设置)"""
|
|
if not os.environ.get(key):
|
|
os.environ[key] = value
|
|
logger.info(f"[Retry] 已设置环境变量 {key}={value}")
|
|
else:
|
|
logger.info(f"[Retry] {key} 已存在,跳过")
|
|
|
|
|
|
class RetryHandler:
|
|
def __init__(self, max_heal: int = 2, max_simple: int = 3):
|
|
self.max_heal = max_heal
|
|
self.max_simple = max_simple
|
|
self.heal_count = 0
|
|
self.simple_count = 0
|
|
self.history: list[VerificationRun] = []
|
|
|
|
def run(self, pipeline_fn: Callable[[], VerificationRun]) -> VerificationRun:
|
|
while (self.heal_count + self.simple_count) < (self.max_heal + self.max_simple):
|
|
vr = pipeline_fn()
|
|
self.history.append(vr)
|
|
|
|
if vr.status in ("PASS", "QUALITY_WARN"):
|
|
vr.heal_retry = self.heal_count
|
|
vr.simple_retry = self.simple_count
|
|
vr.total_retry = self.heal_count + self.simple_count
|
|
return vr
|
|
|
|
if vr.status in ("BLOCKED", "ERROR") and self.heal_count < self.max_heal:
|
|
build_log = vr.debug.get("cobol_build", {}).get("log", "")
|
|
healed = False
|
|
for name, fix_def in HEALING_FIXES.items():
|
|
if fix_def["detect"](build_log):
|
|
fix_def["fix"]()
|
|
self.heal_count += 1
|
|
healed = True
|
|
logger.info(
|
|
f"[Retry] 自愈修复应用: {name} "
|
|
f"(heal_retry={self.heal_count})"
|
|
)
|
|
break
|
|
if healed:
|
|
continue
|
|
|
|
self.simple_count += 1
|
|
logger.info(f"[Retry] 朴素重试 (simple_retry={self.simple_count})")
|
|
|
|
logger.error("[Retry] 重试次数超过上限,标记 FATAL")
|
|
vr = self.history[-1] if self.history else VerificationRun(
|
|
status="FATAL", exit_code=4
|
|
)
|
|
vr.status = "FATAL"
|
|
vr.exit_code = 4
|
|
vr.heal_retry = self.heal_count
|
|
vr.simple_retry = self.simple_count
|
|
vr.total_retry = self.heal_count + self.simple_count
|
|
return vr
|