// tools/taskTimer.js require('dotenv').config(); const db = require('../db/knex'); const { runCycle: runFaceClusteringCycle, } = require( './runFaceClusteringScheduler' ); const { cleanupCast, } = require( './cleanupCast' ); /* * Face clustering: * ogni ora. */ const CLUSTER_INTERVAL_MS = 60 * 60 * 1000; /* * Cleanup Cast: * una volta al giorno. */ const CLEANUP_INTERVAL_MS = 24 * 60 * 60 * 1000; let clusterRunning = false; let cleanupRunning = false; /* * ============================================================ * FACE CLUSTERING * ============================================================ */ async function runClustering() { if (clusterRunning) { console.log( '[taskTimer] clustering already running, skip' ); return; } clusterRunning = true; const startedAt = Date.now(); console.log( '[taskTimer] clustering cycle start' ); try { await runFaceClusteringCycle(); console.log( '[taskTimer] clustering cycle completed', `elapsedMs=${Date.now() - startedAt}`, ); } catch (error) { console.error( '[taskTimer] clustering cycle error', error, ); } finally { clusterRunning = false; } } /* * ============================================================ * CLEANUP CAST * ============================================================ */ async function runCleanup() { if (cleanupRunning) { console.log('[taskTimer] cleanup already running, skip'); return; } cleanupRunning = true; const startedAt = Date.now(); console.log('[taskTimer] cleanup cycle start'); try { // Mantiene la pulizia HLS/Cast esistente. try { await cleanupCast({ dryRun: false }); } catch (error) { console.error('[taskTimer] cleanup Cast error', error); } // Elimina solo job terminali completati da oltre 24 ore. for (const table of [ 'photo_ingest_jobs', 'activity_ingest_jobs', ]) { try { if (!(await db.schema.hasTable(table))) { console.warn(`[taskTimer] table not found: ${table}`); continue; } const deleted = await db(table) .whereIn('status', ['done', 'error']) .whereNotNull('completed_at') .whereRaw( "datetime(completed_at) < datetime('now', '-24 hours')" ) .del(); console.log( `[taskTimer] ${table}: removed ${deleted} expired jobs` ); } catch (error) { console.error(`[taskTimer] ${table} cleanup error`, error); } } console.log( '[taskTimer] cleanup cycle completed', `elapsedMs=${Date.now() - startedAt}`, ); } finally { cleanupRunning = false; } } /* * ============================================================ * MAIN * ============================================================ */ async function main() { console.log( '[taskTimer] started' ); console.log( '[taskTimer] clustering interval:', `${CLUSTER_INTERVAL_MS / 60000} minutes`, ); console.log( '[taskTimer] cleanup interval:', `${CLEANUP_INTERVAL_MS / 3600000} hours`, ); /* * Clustering immediato all'avvio. */ await runClustering(); /* * Cleanup anche all'avvio. * * ATTENZIONE: * cleanupCast garantisce comunque che file * con meno di 24 ore non vengano cancellati. */ await runCleanup(); setInterval( () => { void runClustering(); }, CLUSTER_INTERVAL_MS, ); setInterval( () => { void runCleanup(); }, CLEANUP_INTERVAL_MS, ); console.log( '[taskTimer] timers armed' ); } main().catch((error) => { console.error( '[taskTimer] fatal error', error, ); process.exitCode = 1; });