80 lines
2.1 KiB
JavaScript
80 lines
2.1 KiB
JavaScript
/**
|
|
* Flush memory tier1 (downsampled) points into HyperDB warm storage.
|
|
*
|
|
* Called from the pipeline when the in-memory store rolls a tier1 bucket,
|
|
* or on a periodic timer as a safety net.
|
|
*
|
|
* Cardinality gate: only static catalog charts are persisted by default
|
|
* (see isWarmPersistableChart). Instance charts remain in RAM rings only.
|
|
*/
|
|
import { getDb } from '../db/index.js'
|
|
import { isWarmPersistableChart } from '../../shared/metrics.js'
|
|
import logger from '../utils/logger.js'
|
|
|
|
const log = logger.child('warm-flush')
|
|
|
|
/** @type {Array<{ chart: string, context: string, ts: number, values: object }>} */
|
|
let pending = []
|
|
let flushing = false
|
|
let skippedHighCardinality = 0
|
|
|
|
/**
|
|
* Queue a warm point for HyperDB persistence.
|
|
* @param {{ chart: string, context: string, ts: number, values: object }} point
|
|
*/
|
|
export function enqueueWarmPoint(point) {
|
|
if (!isWarmPersistableChart(point.chart)) {
|
|
skippedHighCardinality++
|
|
return
|
|
}
|
|
pending.push({
|
|
chart: point.chart,
|
|
context: point.context || point.chart,
|
|
ts: point.ts,
|
|
values: point.values,
|
|
tier: 1,
|
|
})
|
|
}
|
|
|
|
/** @returns {{ pending: number, skippedHighCardinality: number }} */
|
|
export function warmFlushStats() {
|
|
return { pending: pending.length, skippedHighCardinality }
|
|
}
|
|
|
|
/**
|
|
* Flush pending warm points to HyperDB.
|
|
*/
|
|
export async function flushWarmPending() {
|
|
const db = getDb()
|
|
if (!db || !pending.length || flushing) return { inserted: 0 }
|
|
flushing = true
|
|
const batch = pending
|
|
pending = []
|
|
try {
|
|
const res = await db.putMetricPoints(batch)
|
|
log.debug?.('Flushed warm points', res)
|
|
return res
|
|
} catch (err) {
|
|
// re-queue on failure (bounded)
|
|
pending = batch.concat(pending).slice(-5000)
|
|
log.error('Warm flush failed', { error: err.message, requeued: batch.length })
|
|
return { inserted: 0, error: err.message }
|
|
} finally {
|
|
flushing = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Persist an anomaly/alert event to HyperDB.
|
|
* @param {object} ev
|
|
*/
|
|
export async function persistAlertEvent(ev) {
|
|
const db = getDb()
|
|
if (!db) return
|
|
try {
|
|
await db.putAlertEvent(ev)
|
|
} catch (err) {
|
|
log.warn('Failed to persist alert event', { error: err.message })
|
|
}
|
|
}
|