diff --git a/src/http/metrics.ts b/src/http/metrics.ts index edc5133..8a2af1c 100644 --- a/src/http/metrics.ts +++ b/src/http/metrics.ts @@ -28,6 +28,75 @@ export async function handleMetricsRequest(request: Request, db: Database): Prom Metrics.set('allowed_groups_total_blocked', blocked); } catch {} + // Métricas de tareas (gauges derivadas desde BD) + try { + const row = db + .prepare(` + SELECT + COUNT(*) AS total, + SUM(CASE WHEN COALESCE(completed, 0) = 1 THEN 1 ELSE 0 END) AS completed, + SUM(CASE WHEN COALESCE(completed, 0) = 0 THEN 1 ELSE 0 END) AS active, + SUM( + CASE + WHEN COALESCE(completed, 0) = 0 + AND due_date IS NOT NULL + AND TRIM(due_date) <> '' + AND due_date < strftime('%Y-%m-%d','now') + THEN 1 ELSE 0 + END + ) AS overdue + FROM tasks; + `) + .get() as any; + + if (row) { + const total = Number(row.total ?? 0); + const completed = Number(row.completed ?? 0); + const active = Number(row.active ?? 0); + const overdue = Number(row.overdue ?? 0); + + Metrics.set('tasks_created_total', total); + Metrics.set('tasks_completed_total', completed); + Metrics.set('tasks_active', active); + Metrics.set('tasks_overdue', overdue); + } + } catch {} + + // Métricas de cola de respuestas (gauges derivadas desde BD) + try { + const row = db + .prepare(` + SELECT + COUNT(*) AS pending, + MIN(strftime('%s', created_at)) AS oldest_ts, + strftime('%s','now') AS now_ts + FROM response_queue + WHERE status = 'queued'; + `) + .get() as any; + + if (row) { + const pending = Number(row.pending ?? 0); + Metrics.set('response_queue_pending', pending); + + let ageSeconds = -1; + const oldestTs = row.oldest_ts != null ? Number(row.oldest_ts) : null; + const nowTs = row.now_ts != null ? Number(row.now_ts) : null; + + if ( + pending > 0 && + oldestTs != null && + Number.isFinite(oldestTs) && + nowTs != null && + Number.isFinite(nowTs) + ) { + ageSeconds = Math.max(0, nowTs - oldestTs); + } + + Metrics.set('response_queue_oldest_age_seconds', ageSeconds); + } + } catch {} + // Exponer métrica con el tiempo restante hasta el próximo group sync (o -1 si scheduler inactivo) try { const secs = GroupSyncService.getSecondsUntilNextGroupSync();