This commit is contained in:
legop3
2026-04-28 19:53:10 -04:00
parent f13b85109e
commit 49f801330f
59 changed files with 686 additions and 401 deletions
@@ -0,0 +1,92 @@
// health Service
// Purpose: Defines the health Service module and the helpers/state used by this service unit.
// Scope: Keeps runtime behavior unchanged while isolating responsibilities into a clear module boundary.
const fsp = require('fs/promises');
const path = require('path');
const roverManager = require('../roverManager');
const { getRoomCameras } = require('../roomCameraService');
const { getRoomCameraState } = require('../roomCameraSnapshotService');
const { getReplayHealthSnapshot } = require('../replayEngineV2');
const ROVER_SNAPSHOT_DIR = process.env.ROVER_SNAPSHOT_DIR || '/var/lib/rover-snapshots';
const HEALTH_INTERVAL_MS = 5000;
const ROOM_CAMERA_STALE_MS = 5000;
const ROVER_SNAPSHOT_STALE_MS = 5000;
let latest = {
updatedAt: Date.now(),
replay: { sources: [], readyCount: 0, totalCount: 0 },
snapshots: { rovers: [], rooms: [] },
};
function collectReplayHealth() {
return getReplayHealthSnapshot();
}
async function collectSnapshotHealth(now) {
const rovers = roverManager.getRoster().map((rover) => ({
id: String(rover.id),
name: rover.name || rover.id,
}));
const roverSnapshots = [];
for (const rover of rovers) {
const filePath = path.join(ROVER_SNAPSHOT_DIR, `${rover.id}.jpg`);
let exists = false;
let size = 0;
let updatedAt = null;
try {
const stat = await fsp.stat(filePath);
exists = true;
size = stat.size;
updatedAt = stat.mtimeMs;
} catch {
// missing snapshot
}
const ageMs = updatedAt ? now - updatedAt : null;
const stale = ageMs != null ? ageMs > ROVER_SNAPSHOT_STALE_MS : true;
roverSnapshots.push({
id: rover.id,
name: rover.name,
exists,
size,
updatedAt,
ageMs,
stale,
});
}
const roomSnapshots = getRoomCameras().map((camera) => {
const state = getRoomCameraState(camera.id);
const updatedAt = state?.ts || null;
const ageMs = updatedAt ? now - updatedAt : null;
const stale = ageMs != null ? ageMs > ROOM_CAMERA_STALE_MS : true;
return {
id: camera.id,
name: camera.name || camera.id,
updatedAt,
ageMs,
error: state?.error || null,
stale,
};
});
return { rovers: roverSnapshots, rooms: roomSnapshots };
}
async function refreshHealth() {
const now = Date.now();
const replay = collectReplayHealth(now);
const snapshots = await collectSnapshotHealth(now);
latest = { updatedAt: now, replay, snapshots };
}
refreshHealth();
setInterval(refreshHealth, HEALTH_INTERVAL_MS);
function getHealthSnapshot() {
return latest;
}
module.exports = {
getHealthSnapshot,
};