mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 15:04:14 +00:00
feat(monitoring): add snapshot collector to queue worker
Periodic metric collection running in the queue-worker PM2 process. Collects system metrics every 60s (configurable), stores them in MonitoringSnapshots, and evaluates alert rules against each snapshot. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d252ed321a
commit
0615b22188
3 changed files with 74 additions and 0 deletions
|
|
@ -39,6 +39,8 @@ module.exports = {
|
||||||
// Worker aktivieren/deaktivieren
|
// Worker aktivieren/deaktivieren
|
||||||
QUEUE_ENABLE_EMAIL: 'true',
|
QUEUE_ENABLE_EMAIL: 'true',
|
||||||
QUEUE_ENABLE_PDF: 'true',
|
QUEUE_ENABLE_PDF: 'true',
|
||||||
|
QUEUE_ENABLE_MONITORING: 'true',
|
||||||
|
MONITORING_SNAPSHOT_INTERVAL: '60000',
|
||||||
// PDF-spezifische Optionen
|
// PDF-spezifische Optionen
|
||||||
PDF_OUTPUT_DIR: '/tmp/payload-pdfs',
|
PDF_OUTPUT_DIR: '/tmp/payload-pdfs',
|
||||||
// PDF_GENERATION_DISABLED: 'true', // Für Tests
|
// PDF_GENERATION_DISABLED: 'true', // Für Tests
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@ async function main() {
|
||||||
const ENABLE_RETENTION_SCHEDULER = process.env.QUEUE_ENABLE_RETENTION_SCHEDULER !== 'false'
|
const ENABLE_RETENTION_SCHEDULER = process.env.QUEUE_ENABLE_RETENTION_SCHEDULER !== 'false'
|
||||||
const ENABLE_YOUTUBE_UPLOAD_WORKER = process.env.QUEUE_ENABLE_YOUTUBE_UPLOAD !== 'false'
|
const ENABLE_YOUTUBE_UPLOAD_WORKER = process.env.QUEUE_ENABLE_YOUTUBE_UPLOAD !== 'false'
|
||||||
|
|
||||||
|
// Monitoring (optional)
|
||||||
|
const ENABLE_MONITORING = process.env.QUEUE_ENABLE_MONITORING !== 'false'
|
||||||
|
|
||||||
console.log('='.repeat(50))
|
console.log('='.repeat(50))
|
||||||
console.log('[QueueRunner] Starting queue workers...')
|
console.log('[QueueRunner] Starting queue workers...')
|
||||||
console.log(`[QueueRunner] PID: ${process.pid}`)
|
console.log(`[QueueRunner] PID: ${process.pid}`)
|
||||||
|
|
@ -52,6 +55,7 @@ async function main() {
|
||||||
console.log(`[QueueRunner] Retention Worker: ${ENABLE_RETENTION_WORKER ? 'enabled' : 'disabled'}`)
|
console.log(`[QueueRunner] Retention Worker: ${ENABLE_RETENTION_WORKER ? 'enabled' : 'disabled'}`)
|
||||||
console.log(`[QueueRunner] Retention Scheduler: ${ENABLE_RETENTION_SCHEDULER ? 'enabled' : 'disabled'}`)
|
console.log(`[QueueRunner] Retention Scheduler: ${ENABLE_RETENTION_SCHEDULER ? 'enabled' : 'disabled'}`)
|
||||||
console.log(`[QueueRunner] YouTube Upload Worker: ${ENABLE_YOUTUBE_UPLOAD_WORKER ? 'enabled' : 'disabled'}`)
|
console.log(`[QueueRunner] YouTube Upload Worker: ${ENABLE_YOUTUBE_UPLOAD_WORKER ? 'enabled' : 'disabled'}`)
|
||||||
|
console.log(`[QueueRunner] Monitoring Collector: ${ENABLE_MONITORING ? 'enabled' : 'disabled'}`)
|
||||||
console.log('='.repeat(50))
|
console.log('='.repeat(50))
|
||||||
|
|
||||||
// Workers starten
|
// Workers starten
|
||||||
|
|
@ -78,6 +82,15 @@ async function main() {
|
||||||
startYouTubeUploadWorker()
|
startYouTubeUploadWorker()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Monitoring Snapshot Collector
|
||||||
|
if (ENABLE_MONITORING) {
|
||||||
|
const { startSnapshotCollector, stopSnapshotCollector } = await import('../src/lib/monitoring/snapshot-collector')
|
||||||
|
await startSnapshotCollector()
|
||||||
|
|
||||||
|
// Store stop function for shutdown
|
||||||
|
;(global as any).__stopSnapshotCollector = stopSnapshotCollector
|
||||||
|
}
|
||||||
|
|
||||||
// Graceful Shutdown
|
// Graceful Shutdown
|
||||||
async function shutdown(signal: string) {
|
async function shutdown(signal: string) {
|
||||||
console.log(`\n[QueueRunner] Received ${signal}, shutting down gracefully...`)
|
console.log(`\n[QueueRunner] Received ${signal}, shutting down gracefully...`)
|
||||||
|
|
@ -97,6 +110,9 @@ async function main() {
|
||||||
if (ENABLE_YOUTUBE_UPLOAD_WORKER) {
|
if (ENABLE_YOUTUBE_UPLOAD_WORKER) {
|
||||||
stopPromises.push(stopYouTubeUploadWorker())
|
stopPromises.push(stopYouTubeUploadWorker())
|
||||||
}
|
}
|
||||||
|
if (ENABLE_MONITORING && (global as any).__stopSnapshotCollector) {
|
||||||
|
stopPromises.push((global as any).__stopSnapshotCollector())
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all(stopPromises)
|
await Promise.all(stopPromises)
|
||||||
console.log('[QueueRunner] All workers stopped')
|
console.log('[QueueRunner] All workers stopped')
|
||||||
|
|
|
||||||
56
src/lib/monitoring/snapshot-collector.ts
Normal file
56
src/lib/monitoring/snapshot-collector.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* Snapshot Collector
|
||||||
|
*
|
||||||
|
* Periodische Metrik-Erfassung, laeuft im Queue-Worker PM2-Prozess.
|
||||||
|
* Sammelt alle 60s (konfigurierbar) System-Metriken und speichert
|
||||||
|
* sie in MonitoringSnapshots. Evaluiert dabei Alert-Regeln.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { collectMetrics } from './monitoring-service.js'
|
||||||
|
import { AlertEvaluator } from './alert-evaluator.js'
|
||||||
|
|
||||||
|
let interval: ReturnType<typeof setInterval> | null = null
|
||||||
|
const alertEvaluator = new AlertEvaluator()
|
||||||
|
|
||||||
|
export async function startSnapshotCollector(): Promise<void> {
|
||||||
|
const INTERVAL = parseInt(process.env.MONITORING_SNAPSHOT_INTERVAL || '60000', 10)
|
||||||
|
console.log(`[SnapshotCollector] Starting (interval: ${INTERVAL}ms)`)
|
||||||
|
|
||||||
|
// Run immediately once, then on interval
|
||||||
|
await collectAndSave()
|
||||||
|
|
||||||
|
interval = setInterval(async () => {
|
||||||
|
await collectAndSave()
|
||||||
|
}, INTERVAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function collectAndSave(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const { getPayload } = await import('payload')
|
||||||
|
const config = (await import('@payload-config')).default
|
||||||
|
const payload = await getPayload({ config })
|
||||||
|
|
||||||
|
const metrics = await collectMetrics()
|
||||||
|
|
||||||
|
await payload.create({
|
||||||
|
collection: 'monitoring-snapshots',
|
||||||
|
data: {
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
...metrics,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Evaluate alert rules against collected metrics
|
||||||
|
await alertEvaluator.evaluateRules(payload, metrics)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[SnapshotCollector] Error:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function stopSnapshotCollector(): Promise<void> {
|
||||||
|
if (interval) {
|
||||||
|
clearInterval(interval)
|
||||||
|
interval = null
|
||||||
|
}
|
||||||
|
console.log('[SnapshotCollector] Stopped')
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue