import { query, pool } from '../db'; export const MECHANIC_OPS = { // 1. DIAGNOSTICS (The Stethoscope) getHealth: async () => { const connections = await query(` SELECT count(*)::int as active, state FROM pg_stat_activity GROUP BY state; `); const size = await query(` SELECT pg_size_pretty(pg_database_size(current_database())) as size; `); // Note: pg_statio_user_tables requires stats collection to be enabled (default on) const cache = await query(` SELECT sum(heap_blks_read) as disk_read, sum(heap_blks_hit) as mem_hit, sum(heap_blks_hit) / NULLIF((sum(heap_blks_hit) + sum(heap_blks_read)), 0)::float as ratio FROM pg_statio_user_tables; `); return { connections: connections.rows, size: size.rows[0]?.size || 'Unknown', cache: cache.rows[0] || { ratio: 0 } }; }, // 2. THE "RED BUTTON" COMMANDS (Fix It) maintenance: { vacuum: async () => { // Cleans up dead rows and optimizes speed await query('VACUUM (VERBOSE, ANALYZE);'); return "Vacuum Complete: DB optimized."; }, reindex: async () => { // Fixes corrupted or slow indexes await query('REINDEX DATABASE directus;'); return "Reindex Complete: Indexes rebuilt."; }, kill_locks: async () => { // Kills any query running longer than 5 minutes const res = await query(` SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'active' AND (now() - query_start) > interval '5 minutes'; `); return `Panic Protocol: Terminated ${res.rowCount} stuck processes.`; } } }; /** * Kill stuck database locks/queries * Returns number of processes terminated */ export async function killLocks(): Promise { const result = await query(` SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'active' AND query_start < NOW() - INTERVAL '30 seconds' AND pid <> pg_backend_pid() `); console.log(`🔧 [Mechanic] Killed ${result.rowCount} stuck processes`); return result.rowCount || 0; } /** * Run VACUUM ANALYZE on a table or entire database * NOTE: Must be run outside of transaction */ export async function vacuumAnalyze(tableName?: string): Promise { const client = await pool.connect(); try { const table = tableName || ''; const sql = table ? `VACUUM ANALYZE ${table}` : 'VACUUM ANALYZE'; console.log(`🔧 [Mechanic] Running: ${sql}`); await client.query(sql); console.log(`✅ [Mechanic] Vacuum complete`); } finally { client.release(); } } /** * Get table bloat statistics */ export async function getTableBloat(): Promise { const result = await query(` SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size, n_dead_tup as dead_rows, n_live_tup as live_rows, CASE WHEN n_live_tup > 0 THEN round(100.0 * n_dead_tup / n_live_tup, 2) ELSE 0 END as bloat_pct FROM pg_stat_user_tables WHERE n_dead_tup > 0 ORDER BY n_dead_tup DESC LIMIT 20 `); return result.rows; }