補 PPT 視覺 QA stale recovery
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s
This commit is contained in:
@@ -150,6 +150,7 @@ def _record_audit_run(run: Dict[str, Any]) -> Dict[str, Any]:
|
||||
global _LAST_AUDIT_RUN
|
||||
payload = dict(run)
|
||||
payload['updated_at'] = payload.get('updated_at') or _now_label()
|
||||
payload['pid'] = payload.get('pid') or os.getpid()
|
||||
_LAST_AUDIT_RUN = payload
|
||||
_write_persisted_audit_run(payload)
|
||||
return payload
|
||||
@@ -176,13 +177,40 @@ def _timestamp_age_seconds(value: str | None) -> float | None:
|
||||
return None
|
||||
|
||||
|
||||
def _pid_exists(pid: Any) -> bool:
|
||||
try:
|
||||
pid_int = int(pid or 0)
|
||||
except Exception:
|
||||
return False
|
||||
if pid_int <= 0:
|
||||
return False
|
||||
try:
|
||||
os.kill(pid_int, 0)
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def _is_recent_active_audit_run(run: Dict[str, Any] | None) -> bool:
|
||||
if not run or run.get('status') not in {'queued', 'running'}:
|
||||
return False
|
||||
if run.get('pid') and not _pid_exists(run.get('pid')):
|
||||
return False
|
||||
age = _timestamp_age_seconds(run.get('updated_at') or run.get('started_at') or run.get('queued_at'))
|
||||
return age is None or age < _ACTIVE_AUDIT_TTL_SECONDS
|
||||
|
||||
|
||||
def _mark_stale_audit_run(run: Dict[str, Any]) -> Dict[str, Any]:
|
||||
payload = dict(run)
|
||||
payload.update({
|
||||
'ok': False,
|
||||
'status': 'error',
|
||||
'finished_at': payload.get('finished_at') or _now_label(),
|
||||
'error': 'background worker no longer running; audit state marked stale',
|
||||
})
|
||||
return _record_audit_run(payload)
|
||||
|
||||
|
||||
def _is_vision_infra_error(error: str | None) -> bool:
|
||||
text = (error or '').lower()
|
||||
return any(marker in text for marker in (
|
||||
@@ -214,6 +242,7 @@ def _public_audit_run_payload(run: Dict[str, Any] | None) -> Dict[str, Any] | No
|
||||
'started_at': run.get('started_at') or '',
|
||||
'finished_at': run.get('finished_at') or '',
|
||||
'updated_at': run.get('updated_at') or '',
|
||||
'pid': run.get('pid') or None,
|
||||
'filenames': [
|
||||
os.path.basename(str(name))
|
||||
for name in (run.get('filenames') or [])
|
||||
@@ -235,6 +264,8 @@ def _public_audit_run_payload(run: Dict[str, Any] | None) -> Dict[str, Any] | No
|
||||
def get_ppt_vision_audit_status() -> Dict[str, Any]:
|
||||
"""Return the current/last background visual QA run without touching DB."""
|
||||
raw_run = _load_last_audit_run()
|
||||
if raw_run and raw_run.get('status') in {'queued', 'running'} and not _is_recent_active_audit_run(raw_run):
|
||||
raw_run = _mark_stale_audit_run(raw_run)
|
||||
running = _AUDIT_LOCK.locked() or _is_recent_active_audit_run(raw_run)
|
||||
last_run = _public_audit_run_payload(raw_run)
|
||||
if running:
|
||||
|
||||
Reference in New Issue
Block a user