/**
 * Watchdog for async gate jobs and (future) workforce workers.
 *
 * Two responsibilities:
 *   1. AsyncGate stale jobs — if a background job runs >3x its etaMs (or >120s
 *      with no eta), mark it failed so poll callers get a clear error.
 *   2. Workforce workers (stub) — once B1 schema ships, wired here to reclaim
 *      jobs from silently-dead workers.
 *
 * Start once at server init via startWatchdog(). The interval unref()s so it
 * won't block process exit.
 */
import { getAsyncGate } from './async-gate.js';
import { nexusEventBus } from '../../../engines/event-bus.js';
import { getWorkforce } from '../../../workforce/index.js';
// ─── Config ───────────────────────────────────────────────────────────────────
const PATROL_INTERVAL_MS = 10_000;
const DEFAULT_STALE_MS = 120_000; // jobs with no eta stale after 2m
const ETA_MULTIPLIER = 3; // jobs stale after 3× their eta
// ─── Async gate job reaper ────────────────────────────────────────────────────
function reapStaleJobs() {
    const gate = getAsyncGate();
    const now = Date.now();
    // Access internal jobs via public getJob on all tracked IDs.
    // AsyncGate doesn't expose iteration, so we probe known running jobs
    // via the event bus history — instead, we expose a minimal method below.
    // (See note: getStaleJobs added to AsyncGate in async-gate.ts)
    const stale = gate.getStaleJobs(now, DEFAULT_STALE_MS, ETA_MULTIPLIER);
    for (const job of stale) {
        gate.markFailed(job.runId, 'watchdog: job exceeded stale timeout');
        nexusEventBus.emit('async_gate.failed', {
            runId: job.runId,
            tool: job.tool,
            error: 'watchdog stale timeout',
        });
    }
}
// ─── Workforce worker watchdog (stub — wired in B1) ──────────────────────────
/** Reclaim expired job leases and mark stale workers. */
function patrolWorkforce() {
    try {
        const wf = getWorkforce();
        wf.markStaleWorkers(30);
        wf.reclaimExpiredLocks();
    }
    catch { /* degraded — non-fatal */ }
}
// ─── Main watchdog loop ───────────────────────────────────────────────────────
let _timer = null;
export function startWatchdog() {
    if (_timer)
        return; // already running
    _timer = setInterval(() => {
        try {
            reapStaleJobs();
        }
        catch { /* non-fatal */ }
        try {
            patrolWorkforce();
        }
        catch { /* non-fatal */ }
    }, PATROL_INTERVAL_MS);
    _timer.unref();
}
export function stopWatchdog() {
    if (_timer) {
        clearInterval(_timer);
        _timer = null;
    }
}
