Files
router-lists-ui/backend/services/uptimeMonitorScheduler.js
T
2026-02-22 21:10:50 +07:00

143 lines
4.6 KiB
JavaScript

/**
* Планировщик проверок Uptime Monitor.
* Периодически вызывает POST /api/uptime/check для каждого jumphost/home и обновляет кеш в S3.
* После перезапуска контейнера кеш обновляется по расписанию без необходимости открывать страницу.
*/
const { readS3TextObject } = require('./s3Service');
const UI_SETTINGS_KEY = 'bgp_data/rt_ui_settings.json';
const DEFAULT_INTERVAL_MINUTES = 2;
const PARALLEL_CHECKS = 2;
let schedulerTimer = null;
let lastScheduledRunAt = null;
function getSettingsFromUiSettings(uiSettings) {
return {
enabled: uiSettings.uptimeMonitorSchedulerEnabled !== false,
intervalMinutes: Math.max(1, Math.min(1440, parseInt(uiSettings.uptimeMonitorSchedulerIntervalMinutes, 10) || DEFAULT_INTERVAL_MINUTES)),
};
}
function getNextRunAt(settings) {
if (!settings || !settings.enabled) return null;
const intervalMs = (settings.intervalMinutes || DEFAULT_INTERVAL_MINUTES) * 60 * 1000;
const from = lastScheduledRunAt || Date.now();
return from + intervalMs;
}
/**
* Запустить планировщик Uptime Monitor.
* @param {object} logger - pino logger
* @param {number} port - порт приложения для вызова API
*/
function initUptimeMonitorScheduler(logger, port) {
const log = logger || console;
const baseUrl = `http://127.0.0.1:${port}`;
async function runChecks(serverIds) {
const runOne = async (serverId) => {
try {
const res = await fetch(`${baseUrl}/api/uptime/check`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ serverId }),
});
if (!res.ok) {
log.warn({ component: 'uptime-monitor-scheduler', serverId, status: res.status }, 'Uptime check failed');
}
} catch (err) {
log.warn({ component: 'uptime-monitor-scheduler', serverId, err: err?.message }, 'Uptime check error');
}
};
for (let i = 0; i < serverIds.length; i += PARALLEL_CHECKS) {
const chunk = serverIds.slice(i, i + PARALLEL_CHECKS);
await Promise.all(chunk.map(runOne));
}
}
async function tick() {
lastScheduledRunAt = Date.now();
let uiSettings;
try {
const raw = await readS3TextObject(UI_SETTINGS_KEY).catch(() => ({ body: '{}' }));
uiSettings = JSON.parse(raw?.body || '{}') || {};
} catch (_) {
return;
}
const settings = getSettingsFromUiSettings(uiSettings);
if (!settings.enabled) return;
let servers = [];
try {
const res = await fetch(`${baseUrl}/api/servers`);
const data = res.ok ? await res.json() : [];
servers = Array.isArray(data) ? data : [];
} catch (err) {
log.error({ component: 'uptime-monitor-scheduler', err: err?.message }, 'Failed to fetch servers');
return;
}
const jumphosts = servers.filter(
(s) => s && ['jumphost', 'home'].includes(String(s.type || '').toLowerCase())
);
const serverIds = jumphosts
.map((s) => s.id || s.dns || s.ip)
.filter(Boolean);
if (serverIds.length === 0) {
log.info({ component: 'uptime-monitor-scheduler' }, 'No jumphost/home servers to check');
return;
}
log.info(
{ component: 'uptime-monitor-scheduler', count: serverIds.length },
'Running uptime monitor checks for %d server(s)',
serverIds.length
);
await runChecks(serverIds);
}
async function schedule() {
let uiSettings;
try {
const raw = await readS3TextObject(UI_SETTINGS_KEY).catch(() => ({ body: '{}' }));
uiSettings = JSON.parse(raw?.body || '{}') || {};
} catch (_) {
return;
}
const settings = getSettingsFromUiSettings(uiSettings);
if (!settings.enabled) {
log.info({ component: 'uptime-monitor-scheduler' }, 'Uptime monitor scheduler disabled in settings');
return;
}
const intervalMs = settings.intervalMinutes * 60 * 1000;
log.info(
{ component: 'uptime-monitor-scheduler', intervalMinutes: settings.intervalMinutes },
'Uptime monitor scheduler started (first run in 20 s, then every %d min)',
settings.intervalMinutes
);
schedulerTimer = setInterval(tick, intervalMs);
setTimeout(() => tick(), 20 * 1000);
}
schedule();
}
function stopUptimeMonitorScheduler() {
if (schedulerTimer) {
clearInterval(schedulerTimer);
schedulerTimer = null;
}
}
module.exports = {
initUptimeMonitorScheduler,
stopUptimeMonitorScheduler,
getSettingsFromUiSettings,
getNextRunAt,
};