Apply all settings and alerts live without Save buttons
Release rolling / release (push) Has been cancelled
Release rolling / release (push) Has been cancelled
Auto-persist client preferences on change with footer feedback, and apply server alert engine settings/channels/rules immediately.
This commit is contained in:
@@ -1154,6 +1154,7 @@ function armPoll() {
|
||||
clearInterval(pollTimer)
|
||||
pollTimer = null
|
||||
}
|
||||
if (!config.enabled) return
|
||||
const ms = config.pollIntervalMs || DEFAULT_POLL_MS
|
||||
pollTimer = setInterval(() => {
|
||||
pollHealth().catch((err) => {
|
||||
@@ -1163,14 +1164,36 @@ function armPoll() {
|
||||
if (typeof pollTimer.unref === 'function') pollTimer.unref()
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply in-memory config to runtime (poll timer, etc.) without restart.
|
||||
* Called after every config mutation so enable/disable and intervals are live.
|
||||
*/
|
||||
function applyRuntimeConfig({ kickPoll = false } = {}) {
|
||||
armPoll()
|
||||
if (kickPoll && config.enabled) {
|
||||
pollHealth().catch((err) => {
|
||||
logger.debug('alerts: kick poll failed', { error: err.message })
|
||||
})
|
||||
}
|
||||
logger.info('alerts: runtime config applied', {
|
||||
enabled: config.enabled,
|
||||
pollIntervalMs: config.pollIntervalMs,
|
||||
minSeverity: config.minSeverity,
|
||||
rateLimitPerMinute: config.rateLimitPerMinute,
|
||||
quietHours: Boolean(config.quietHours?.enabled),
|
||||
channels: config.channels.filter((c) => c.enabled).length,
|
||||
rules: config.rules.filter((r) => r.enabled).length,
|
||||
})
|
||||
}
|
||||
|
||||
export function startAlerts() {
|
||||
if (started) return
|
||||
started = true
|
||||
loadDisk()
|
||||
armPoll()
|
||||
// Initial poll shortly after boot
|
||||
applyRuntimeConfig({ kickPoll: false })
|
||||
// Initial poll shortly after boot (only if enabled)
|
||||
setTimeout(() => {
|
||||
pollHealth().catch(() => {})
|
||||
if (config.enabled) pollHealth().catch(() => {})
|
||||
}, 5_000)
|
||||
logger.info('Alerts engine started', {
|
||||
channels: config.channels.length,
|
||||
@@ -1216,6 +1239,7 @@ export function getAlertsConfigRaw() {
|
||||
* @param {{ replace?: boolean }} [opts]
|
||||
*/
|
||||
export function updateAlertsConfig(partial, opts = {}) {
|
||||
const wasEnabled = config.enabled
|
||||
if (opts.replace) {
|
||||
config = normalizeConfig(partial)
|
||||
} else {
|
||||
@@ -1237,7 +1261,10 @@ export function updateAlertsConfig(partial, opts = {}) {
|
||||
}
|
||||
config.updatedAt = new Date().toISOString()
|
||||
saveDisk()
|
||||
armPoll()
|
||||
// Live apply: poll interval, enable/disable — no process restart
|
||||
applyRuntimeConfig({
|
||||
kickPoll: config.enabled && (!wasEnabled || partial.pollIntervalMs != null),
|
||||
})
|
||||
return getAlertsConfig()
|
||||
}
|
||||
|
||||
@@ -1258,6 +1285,12 @@ export function upsertAlertChannel(input) {
|
||||
config.channels.push(ch)
|
||||
}
|
||||
scheduleSave()
|
||||
// Channel list is read on each fire — already live; log for ops clarity
|
||||
logger.debug('alerts: channel upserted live', {
|
||||
id: ch.id,
|
||||
enabled: ch.enabled,
|
||||
type: ch.type,
|
||||
})
|
||||
return redactChannel(ch)
|
||||
}
|
||||
|
||||
@@ -1280,6 +1313,11 @@ export function upsertAlertRule(input) {
|
||||
if (idx >= 0) config.rules[idx] = rule
|
||||
else config.rules.push(rule)
|
||||
scheduleSave()
|
||||
logger.debug('alerts: rule upserted live', {
|
||||
id: rule.id,
|
||||
enabled: rule.enabled,
|
||||
kind: rule.kind,
|
||||
})
|
||||
return rule
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user