fix(backend): уменьшить лишние записи SQLite
Docker images / prepare-release (push) Successful in 10s
Docker images / backend-image (push) Successful in 2m8s
Docker images / frontend-image (push) Successful in 3m14s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 47s
Docker images / publish-release (push) Successful in 12s

Убрать WAL TRUNCATE с hot path NetFlow, не писать неизменённые UPDATE
и служебные INSERT, кэшировать карты topology/analytics.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-07 20:22:20 +07:00
co-authored by Cursor
parent 5188b2aff2
commit 0e5fb065e2
20 changed files with 521 additions and 127 deletions
+45 -26
View File
@@ -7,7 +7,7 @@
* 3. `uptime_speed` — ниже (BW-test, тяжёлый); локи узлов — `withBtestNodeLocks` в speed-сервисе.
*
* **Оповещения (`alert_engine`):** читают SQLite после джоб сбора (см. `buildSignalSnapshot`), в т.ч.
* `gre_bgp` → `alert_gre_tunnel_samples` / `alert_bgp_peer_samples`. После успешного завершения джоб
* `gre_bgp` → snapshot в `scheduler_runs.result_json` (`greTunnels` / `bgpPeers`). После успешного завершения джоб
* `traffic`, `uptime_*`, `servers_rest_ping`, `gre_bgp` планируется **дополнительный** прогон движка
* (debounce), см. [`alert-collector-hooks.ts`](./alert-collector-hooks.ts); любой другой писатель сэмплов
* для снимка оповещений тоже должен вызывать `scheduleAlertEngineAfterDataCollectors()` после коммита.
@@ -17,7 +17,7 @@
*/
import { desc, eq, lt } from "drizzle-orm"
import { db } from "../db/index.js"
import { schedulerRuns } from "../db/schema.js"
import { events, schedulerRuns } from "../db/schema.js"
import type { SchedulerRunSnapshot } from "../types/scheduler-run-snapshot.js"
import { SCHEDULER_RUN_SNAPSHOT_VERSION } from "../types/scheduler-run-snapshot.js"
import {
@@ -71,6 +71,20 @@ const timers = new Map<string, ReturnType<typeof setInterval>>()
const RUN_LOG_RETENTION_MS = 30 * 24 * 60 * 60 * 1000
const QUIET_SCHEDULER_OK_JOBS = new Set<SchedulerJobKey>([
"traffic",
"servers_rest_ping",
"uptime_resources",
"uptime_ping",
"uptime_speed",
"gre_bgp",
"alert_engine",
])
export function shouldAppendSchedulerOkEvent(jobKey: SchedulerJobKey): boolean {
return !QUIET_SCHEDULER_OK_JOBS.has(jobKey)
}
function newRunId(): string {
return `sch-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`
}
@@ -84,18 +98,21 @@ function appendSchedulerRun(row: {
durationMs: number
result?: SchedulerRunSnapshot | null
}) {
db.insert(schedulerRuns).values({
id: newRunId(),
jobKey: row.jobKey,
startedAt: row.startedAt,
finishedAt: row.finishedAt,
status: row.status,
error: row.error,
durationMs: row.durationMs,
resultJson: row.result ? JSON.stringify(row.result) : null,
}).run()
const cutoff = new Date(Date.now() - RUN_LOG_RETENTION_MS).toISOString()
db.delete(schedulerRuns).where(lt(schedulerRuns.finishedAt, cutoff)).run()
db.transaction((tx) => {
tx.insert(schedulerRuns).values({
id: newRunId(),
jobKey: row.jobKey,
startedAt: row.startedAt,
finishedAt: row.finishedAt,
status: row.status,
error: row.error,
durationMs: row.durationMs,
resultJson: row.result ? JSON.stringify(row.result) : null,
}).run()
tx.delete(schedulerRuns).where(lt(schedulerRuns.finishedAt, cutoff)).run()
tx.delete(events).where(lt(events.createdAt, cutoff)).run()
})
}
async function runSchedulerJobBody(jobKey: SchedulerJobKey): Promise<void> {
@@ -159,19 +176,21 @@ async function runSchedulerJobBody(jobKey: SchedulerJobKey): Promise<void> {
durationMs: Date.now() - startedAt,
result: snapshot ?? null,
})
appendEvent({
level: "info",
eventType: "scheduler.job.ok",
sourceModule: "scheduler",
title: "Задача планировщика завершена",
message: `${jobKey}: выполнено за ${Date.now() - startedAt} мс`,
entityType: "job",
entityId: jobKey,
payload: {
startedAt: startedIso,
finishedAt: finishedIso,
},
})
if (shouldAppendSchedulerOkEvent(jobKey)) {
appendEvent({
level: "info",
eventType: "scheduler.job.ok",
sourceModule: "scheduler",
title: "Задача планировщика завершена",
message: `${jobKey}: выполнено за ${Date.now() - startedAt} мс`,
entityType: "job",
entityId: jobKey,
payload: {
startedAt: startedIso,
finishedAt: finishedIso,
},
})
}
if (
jobKey === "traffic" ||
jobKey === "servers_rest_ping" ||