import { NextRequest, NextResponse } from 'next/server' import { statsCollectionService } from '@/lib/services/stats-collection-service' import { logScanningService } from '@/lib/services/log-scanning-service' import { containerHealthService } from '@/lib/services/container-health-service' /** * GET /api/cron/collect-stats * Collect stats, scan logs for errors, and check container health for all enterprise servers * * This endpoint is designed to be called by a cron job or scheduled task. * It should be protected by a secret token in production. * * Example cron schedule: Every 5 minutes * Vercel cron config in vercel.json: * { * "crons": [ * { "path": "/api/cron/collect-stats", "schedule": "*\/5 * * * *" } * ] * } * * What this cron does: * 1. Collects performance stats from Netcup + Portainer for all active servers * 2. Scans container logs for errors matching client-defined rules * 3. Checks container health and detects crashes/OOM kills */ export async function GET(request: NextRequest) { // Verify cron secret (for security in production) const cronSecret = process.env.CRON_SECRET const authHeader = request.headers.get('authorization') if (cronSecret && authHeader !== `Bearer ${cronSecret}`) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const startTime = Date.now() const results = { stats: { collected: 0, failed: 0 }, logScan: { totalServers: 0, scannedServers: 0, failedServers: 0, totalErrorsFound: 0, duration: 0 }, healthCheck: { totalServers: 0, checkedServers: 0, failedServers: 0, eventsDetected: 0, crashes: 0, oomKills: 0, duration: 0 }, errors: [] as string[], } // 1. Collect performance stats (existing functionality) try { results.stats = await statsCollectionService.collectAllStats() console.log(`[Cron] Stats collection: ${results.stats.collected} servers, ${results.stats.failed} failed`) } catch (error) { console.error('[Cron] Stats collection failed:', error) results.errors.push(`Stats collection: ${error instanceof Error ? error.message : 'Unknown error'}`) } // 2. Scan container logs for errors try { results.logScan = await logScanningService.scanAllServers() console.log(`[Cron] Log scan: ${results.logScan.scannedServers}/${results.logScan.totalServers} servers, ${results.logScan.totalErrorsFound} errors found`) } catch (error) { console.error('[Cron] Log scanning failed:', error) results.errors.push(`Log scanning: ${error instanceof Error ? error.message : 'Unknown error'}`) } // 3. Check container health (crash detection) try { results.healthCheck = await containerHealthService.checkAllServers() console.log(`[Cron] Health check: ${results.healthCheck.checkedServers}/${results.healthCheck.totalServers} servers, ${results.healthCheck.eventsDetected} events detected`) } catch (error) { console.error('[Cron] Health check failed:', error) results.errors.push(`Health check: ${error instanceof Error ? error.message : 'Unknown error'}`) } const totalDuration = Date.now() - startTime const hasErrors = results.errors.length > 0 return NextResponse.json({ success: !hasErrors, timestamp: new Date().toISOString(), duration: `${totalDuration}ms`, // Stats collection results stats: { serversCollected: results.stats.collected, serversFailed: results.stats.failed, }, // Log scanning results logScan: { serversScanned: results.logScan.scannedServers, serversFailed: results.logScan.failedServers, errorsFound: results.logScan.totalErrorsFound, duration: `${results.logScan.duration}ms`, }, // Health check results healthCheck: { serversChecked: results.healthCheck.checkedServers, serversFailed: results.healthCheck.failedServers, eventsDetected: results.healthCheck.eventsDetected, crashes: results.healthCheck.crashes, oomKills: results.healthCheck.oomKills, duration: `${results.healthCheck.duration}ms`, }, // Any errors that occurred ...(hasErrors && { errors: results.errors }), }, { status: hasErrors ? 207 : 200 }) // 207 Multi-Status if partial failure } // Also support POST for flexibility export async function POST(request: NextRequest) { return GET(request) }