diff --git a/my-tools/show_blender_web_scheduler.py b/my-tools/show_blender_web_scheduler.py index 928eb4a9c..200ac9ce6 100755 --- a/my-tools/show_blender_web_scheduler.py +++ b/my-tools/show_blender_web_scheduler.py @@ -39,6 +39,14 @@ def main() -> int: "watchdogStatus": read_json(CONTROL_ROOT / "my-tools-watchdog.json"), "schedulerWrapperStatus": read_json(CONTROL_ROOT / "my-tools-scheduler.json"), } + watchdog = status["myTools"]["watchdogStatus"] + watchdog_pid = watchdog.get("pid") if isinstance(watchdog, dict) else None + watchdog_alive = isinstance(watchdog_pid, int) and (Path("/proc") / str(watchdog_pid)).exists() + status["myTools"]["watchdogAlive"] = watchdog_alive + status["unattendedState"] = ( + "PLANNING" if status.get("state") == "IDLE" and watchdog_alive and watchdog.get("status") == "waiting_for_source_batch" + else status.get("state", "UNKNOWN") + ) status["progress"] = project_progress() status["fastPath"] = fast_path_status(status) if args.json: @@ -53,7 +61,7 @@ def main() -> int: if args.watch: print("\x1b[2J\x1b[H", end="") print("Blender Web/WBV2 scheduler") - print(f" state: {status.get('state', 'UNKNOWN')}") + print(f" state: {status.get('unattendedState', status.get('state', 'UNKNOWN'))}") print(f" phase: {status.get('phase', 'unknown')}") queue = status.get("queue", {}) print(f" current task: {queue.get('task') or 'none'}") @@ -65,12 +73,15 @@ def main() -> int: print(f" guardian: pid={guardian.get('pid') or 'none'} alive={guardian.get('alive', False)} state={guardian.get('state') or 'unknown'}") print(f" supervisor: pid={supervisor.get('pid') or 'none'} alive={supervisor.get('alive', False)} state={supervisor.get('state') or 'unknown'}") watchdog = status.get("myTools", {}).get("watchdogStatus", {}) - print(f" watchdog: pid={watchdog.get('pid') or 'external'} status={watchdog.get('status') or 'unknown'} reason={watchdog.get('reason') or 'none'} task={watchdog.get('task') or 'none'}") + print(f" watchdog: pid={watchdog.get('pid') or 'none'} alive={status.get('myTools', {}).get('watchdogAlive', False)} status={watchdog.get('status') or 'unknown'} reason={watchdog.get('reason') or 'none'} task={watchdog.get('task') or 'none'}") print(f" latest handoff: {status.get('latestHandoff') or 'none'}") print(f" local HEAD: {status.get('localHead') or 'unknown'}") for line in format_progress(status["progress"], status["fastPath"]): print(line) - print(f" message: {status.get('message', '')}") + if status.get("unattendedState") == "PLANNING": + print(" message: PLANNING: watchdog heartbeat is active; exact source gaps are queued without false coverage.") + else: + print(f" message: {status.get('message', '')}") if not args.watch: return 0 try: diff --git a/my-tools/watch_blender_web_scheduler.py b/my-tools/watch_blender_web_scheduler.py index e1ead8182..5db527b64 100755 --- a/my-tools/watch_blender_web_scheduler.py +++ b/my-tools/watch_blender_web_scheduler.py @@ -32,14 +32,17 @@ def now() -> str: def write_json(path: Path, value: dict) -> None: path.parent.mkdir(parents=True, exist_ok=True) - try: - current = json.loads(path.read_text(encoding="utf-8")) - stable_current = {key: item for key, item in current.items() if key != "updatedAt"} - stable_next = {key: item for key, item in value.items() if key != "updatedAt"} - if stable_current == stable_next: - return - except (OSError, json.JSONDecodeError): - pass + if path == WATCHDOG_STATUS: + value = {**value, "pid": os.getpid()} + else: + try: + current = json.loads(path.read_text(encoding="utf-8")) + stable_current = {key: item for key, item in current.items() if key != "updatedAt"} + stable_next = {key: item for key, item in value.items() if key != "updatedAt"} + if stable_current == stable_next: + return + except (OSError, json.JSONDecodeError): + pass temporary = path.with_suffix(path.suffix + f".tmp-{os.getpid()}") temporary.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") temporary.replace(path)