const fs = require('fs'); const path = require('path'); const db = require('../db/knex'); const LOCK_PATH = path.resolve( __dirname, '..', 'face-scan-daemon.lock', ); function readLock() { try { const text = fs.readFileSync( LOCK_PATH, 'utf8', ); return JSON.parse(text); } catch { return null; } } function isProcessAlive(pidValue) { const pid = Number(pidValue); if ( !Number.isInteger(pid) || pid <= 0 ) { return false; } try { process.kill(pid, 0); return true; } catch (error) { return error.code === 'EPERM'; } } async function getQueueStatus() { const rows = await db('face_scan_jobs') .select('status') .count({ count: '*' }) .groupBy('status'); const queue = { pending: 0, processing: 0, done: 0, error: 0, }; for (const row of rows) { queue[row.status] = Number(row.count || 0); } return queue; } async function getFaceStatistics() { const row = await db('face_scan_jobs') .select( db.raw( 'SUM(COALESCE(faces_detected, 0)) ' + 'AS total_faces', ), db.raw( 'SUM(attempts) AS total_attempts', ), db.raw( 'ROUND(AVG(execution_ms), 1) ' + 'AS average_execution_ms', ), ) .first(); return { total_faces: Number(row?.total_faces || 0), total_attempts: Number(row?.total_attempts || 0), average_execution_ms: row?.average_execution_ms == null ? null : Number(row.average_execution_ms), }; } async function main() { const queue = await getQueueStatus(); const statistics = await getFaceStatistics(); const lock = readLock(); const daemonAlive = lock != null && isProcessAlive(lock.pid); const result = { daemon: { running: daemonAlive, lock_exists: lock != null, lock_path: LOCK_PATH, pid: lock?.pid ?? null, started_at: lock?.started_at ?? null, project_root: lock?.project_root ?? null, stale_lock: lock != null && !daemonAlive, }, queue, statistics, }; console.log( JSON.stringify(result, null, 2), ); } main() .catch((error) => { console.error( '[faceScanStatus] errore:', error.stack || error.message || error, ); process.exitCode = 1; }) .finally(async () => { await db.destroy(); });