From 89d71ff060ea0df676697b3f9a262f6ac46cb90f Mon Sep 17 00:00:00 2001 From: shats Date: Wed, 18 Feb 2026 13:23:03 +0700 Subject: [PATCH] feat(NetworkMapScheduler): enhance job execution logging and add force refresh option for ping and speed tests --- backend/routes/mikrotikConfigRoutes.js | 4 +++- backend/routes/schedulerRoutes.js | 9 ++++++++ backend/services/networkMapScheduler.js | 28 ++++++++++++++++++------- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/backend/routes/mikrotikConfigRoutes.js b/backend/routes/mikrotikConfigRoutes.js index e1df7dc..81cb039 100644 --- a/backend/routes/mikrotikConfigRoutes.js +++ b/backend/routes/mikrotikConfigRoutes.js @@ -514,6 +514,7 @@ async function pingViaInterface(req, res) { interfaceName, target, count = 5, + forceRefresh = false, } = req.body || {}; if (!serverId) { @@ -528,7 +529,8 @@ async function pingViaInterface(req, res) { } const pingCacheMinutes = Math.max(0, parseInt(uiSettings.pingCacheMinutes, 10) || 0); const cacheKey = pingCacheMinutes > 0 ? pingCacheKey(serverId, gatewayIp, target) : null; - if (cacheKey) { + const skipCacheRead = forceRefresh === true; + if (!skipCacheRead && cacheKey) { try { const data = await readS3TextObject(cacheKey).catch(() => null); if (data?.body) { diff --git a/backend/routes/schedulerRoutes.js b/backend/routes/schedulerRoutes.js index b992b61..9c4919f 100644 --- a/backend/routes/schedulerRoutes.js +++ b/backend/routes/schedulerRoutes.js @@ -84,13 +84,22 @@ async function runNetworkMapSchedulerNow(req, res) { baseUrl, runPing: settings.runPing, runSpeedTest: settings.runSpeedTest, + trigger: 'manual', }).catch((err) => { console.error('[scheduler] run-now failed', err); + const msg = err?.message || String(err); + try { + networkMapScheduler.pushLog(`Ошибка выполнения: ${msg}`); + } catch (_) {} }); return sendOk(res, { message: 'Запуск выполняется в фоне' }); } catch (e) { console.error('[scheduler] run-now', e); + const msg = e?.message || String(e); + try { + networkMapScheduler.pushLog(`Ошибка запуска: ${msg}`); + } catch (_) {} return sendError(res, 500, 'Не удалось запустить', 'E_SCHEDULER'); } } diff --git a/backend/services/networkMapScheduler.js b/backend/services/networkMapScheduler.js index 7ace435..a2a8e51 100644 --- a/backend/services/networkMapScheduler.js +++ b/backend/services/networkMapScheduler.js @@ -164,10 +164,12 @@ async function runWithOnePerKey(tasks, getKey) { * @param {object} opts - { baseUrl, runPing, runSpeedTest, log } */ async function runJob(opts) { - const { baseUrl, runPing = true, runSpeedTest = true, log = (msg) => logBuffer.push(msg) } = opts; + const { baseUrl, runPing = true, runSpeedTest = true, log = (msg) => logBuffer.push(msg), trigger = 'scheduled' } = opts; const pingMap = {}; const speedMap = {}; + log(trigger === 'manual' ? '--- Ручной запуск ---' : '--- Запуск по расписанию ---'); + try { const { connections, servers } = await buildConnections(); if (connections.length === 0) { @@ -201,12 +203,14 @@ async function runJob(opts) { target: c.internalFromTo, gatewayIp: c.internalFromTo, count: 3, + forceRefresh: true, }), }); const data = await res.json().catch(() => ({})); const ms = typeof data?.avgMs === 'number' ? Math.round(data.avgMs) : null; pingMap[ekey] = ms; - log(`Пинг ${from} → ${to}: ${ms != null ? ms + ' ms' : 'ошибка'}`); + const errMsg = !res.ok ? (data?.message || `HTTP ${res.status}`) : null; + log(`Пинг ${from} → ${to}: ${ms != null ? ms + ' ms' : errMsg || 'ошибка'}`); return ms; } catch (e) { pingMap[ekey] = null; @@ -226,12 +230,14 @@ async function runJob(opts) { target: c.internalToFrom, gatewayIp: c.internalToFrom, count: 3, + forceRefresh: true, }), }); const data = await res.json().catch(() => ({})); const ms = typeof data?.avgMs === 'number' ? Math.round(data.avgMs) : null; pingMap[ekey] = ms; - log(`Пинг ${to} → ${from}: ${ms != null ? ms + ' ms' : 'ошибка'}`); + const errMsg2 = !res.ok ? (data?.message || `HTTP ${res.status}`) : null; + log(`Пинг ${to} → ${from}: ${ms != null ? ms + ' ms' : errMsg2 || 'ошибка'}`); return ms; } catch (e) { pingMap[ekey] = null; @@ -255,11 +261,12 @@ async function runJob(opts) { body: JSON.stringify({ serverId: c.speedTestServerId, interfaceName: c.interfaceName, + forceRefresh: true, }), signal: (() => { - const c = new AbortController(); - setTimeout(() => c.abort(), 120000); - return c.signal; + const ac = new AbortController(); + setTimeout(() => ac.abort(), 120000); + return ac.signal; })(), }); const data = await res.json().catch(() => ({})); @@ -276,7 +283,8 @@ async function runJob(opts) { return speedMap[key]; } speedMap[key] = null; - log(`Скорость ${c.interfaceName}: нет данных`); + const speedErr = !res.ok ? (data?.message || `HTTP ${res.status}`) : 'нет данных'; + log(`Скорость ${c.interfaceName}: ${speedErr}`); return null; } catch (e) { speedMap[key] = null; @@ -402,6 +410,11 @@ function setLogMaxLines(n) { logBuffer.setMaxLines(num); } +/** Добавить строку в лог (для вывода ошибок из роутов) */ +function pushLog(msg) { + logBuffer.push(msg); +} + module.exports = { runJob, initNetworkMapScheduler, @@ -409,6 +422,7 @@ module.exports = { getLogs, getLogMaxLines, setLogMaxLines, + pushLog, getSettingsFromUiSettings, loadUiSettings: loadUiSettings, buildConnections,