fix(api): дождаться запросов перед операцией с базой
This commit is contained in:
1 parent
9264b6636a
commit
8682f2a7a5
12 files changed
+183
-5
No files matched your search
@@ -37,7 +37,7 @@
|
||||
"test:ospf-optimizer": "tsx src/services/ospf-optimizer-identity.test.ts && tsx src/services/ospf-optimizer-metrics.test.ts && tsx src/services/ospf-optimizer-plan.test.ts && tsx src/routes/ospf-optimizer.test.ts",
|
||||
"test:containers": "tsx src/services/containers-state.test.ts && tsx src/routes/containers-state.test.ts",
|
||||
"test:certificates": "tsx src/services/certificate-issue-execution.test.ts && tsx src/services/certificate-issue-request.test.ts && tsx src/routes/certificates-issue.test.ts && tsx src/services/certificate-issue-dto.test.ts && tsx src/services/certificate-parse.test.ts && tsx src/services/certificates-state.test.ts && tsx src/routes/certificates-state.test.ts",
|
||||
"test:system-database": "tsx src/services/traffic-flow-worker-shutdown.test.ts && tsx src/services/system-database-restore-execution.test.ts && tsx src/services/system-database-operation.test.ts && tsx src/routes/system-database.test.ts && tsx src/plugins/auth.system-database.test.ts"
|
||||
"test:system-database": "tsx src/services/database-request-gate.test.ts && tsx src/services/traffic-flow-worker-shutdown.test.ts && tsx src/services/system-database-restore-execution.test.ts && tsx src/services/system-database-operation.test.ts && tsx src/routes/system-database.test.ts && tsx src/plugins/auth.system-database.test.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.888.0",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { env } from "./config.js"
|
||||
import { initDatabase } from "./db/bootstrap.js"
|
||||
import { closePool } from "./db/index.js"
|
||||
import authPlugin, { requireAuth } from "./plugins/auth.js"
|
||||
import { installDatabaseRequestGate } from "./plugins/database-request-gate.js"
|
||||
import serversRoutes from "./routes/servers.js"
|
||||
import bgpRoutes from "./routes/bgp.js"
|
||||
import ospfRoutes from "./routes/ospf.js"
|
||||
@@ -116,6 +117,7 @@ export async function buildApp(opts?: {
|
||||
})
|
||||
}
|
||||
|
||||
installDatabaseRequestGate(app)
|
||||
await app.register(serversRoutes, { prefix: "/api/servers" })
|
||||
await app.register(bgpRoutes, { prefix: "/api" })
|
||||
await app.register(ospfRoutes, { prefix: "/api" })
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { FastifyInstance, FastifyRequest } from "fastify"
|
||||
import { DatabaseRequestGate } from "../services/database-request-gate.js"
|
||||
const streams = new WeakMap<FastifyRequest, { cancelled: boolean; abort?: () => void }>()
|
||||
|
||||
export function registerDatabaseStreamAbort(request: FastifyRequest, abort: () => void): void {
|
||||
const state = streams.get(request)
|
||||
if (!state) return
|
||||
state.abort = abort
|
||||
if (state.cancelled) abort()
|
||||
}
|
||||
|
||||
export function installDatabaseRequestGate(app: FastifyInstance): void {
|
||||
const gate = new DatabaseRequestGate()
|
||||
app.addHook("onRoute", options => {
|
||||
const path = options.url
|
||||
if (!path.startsWith("/api/") || path === "/api/auth/config") return
|
||||
const original = options.handler
|
||||
const operation = path === "/api/system/database/backup" || path === "/api/system/database/restore"
|
||||
const stream = path === "/api/traffic/flow/live" || /^\/api\/traffic\/servers\/:id\/live$/.test(path)
|
||||
options.handler = async function (request, reply) {
|
||||
const run = async () => await original.call(this, request, reply)
|
||||
if (operation) return gate.exclusive(run)
|
||||
if (!stream) return gate.request(run)
|
||||
const state = { cancelled: false, abort: undefined as (() => void) | undefined }
|
||||
streams.set(request, state)
|
||||
try {
|
||||
return await gate.request(run, () => { state.cancelled = true; state.abort?.() })
|
||||
} finally { streams.delete(request) }
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { FastifyPluginAsyncZod } from "@fastify/type-provider-zod"
|
||||
import { registerDatabaseStreamAbort } from "../plugins/database-request-gate.js"
|
||||
import type { FastifyReply, FastifyRequest } from "fastify"
|
||||
import { env } from "../config.js"
|
||||
import {
|
||||
@@ -249,6 +250,7 @@ const trafficFlowRoutes: FastifyPluginAsyncZod = async (app) => {
|
||||
}
|
||||
const abort = new AbortController()
|
||||
const onClose = () => abort.abort()
|
||||
registerDatabaseStreamAbort(req, onClose)
|
||||
req.raw.on("close", onClose)
|
||||
|
||||
reply.hijack()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { env } from "../config.js"
|
||||
import { registerDatabaseStreamAbort } from "../plugins/database-request-gate.js"
|
||||
import { desc, eq } from "drizzle-orm"
|
||||
import type { FastifyPluginAsyncZod } from "@fastify/type-provider-zod"
|
||||
import { db } from "../db/index.js"
|
||||
@@ -322,6 +323,7 @@ const trafficRoutes: FastifyPluginAsyncZod = async (app) => {
|
||||
const onlyInterface = q.iface && q.iface !== "__all__" ? q.iface : undefined
|
||||
const abort = new AbortController()
|
||||
const onClose = () => abort.abort()
|
||||
registerDatabaseStreamAbort(req, onClose)
|
||||
req.raw.on("close", onClose)
|
||||
|
||||
reply.hijack()
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { test } from "node:test"
|
||||
import Fastify from "fastify"
|
||||
import { DatabaseRequestGate } from "./database-request-gate.js"
|
||||
import { installDatabaseRequestGate, registerDatabaseStreamAbort } from "../plugins/database-request-gate.js"
|
||||
|
||||
function deferred() {
|
||||
let resolve!: () => void
|
||||
const promise = new Promise<void>(r => { resolve = r })
|
||||
return { promise, resolve }
|
||||
}
|
||||
|
||||
test("exclusive operation waits for handler settlement and blocks new requests", async () => {
|
||||
const gate = new DatabaseRequestGate(), pending = deferred(), entered = deferred()
|
||||
const request = gate.request(async () => { entered.resolve(); await pending.promise })
|
||||
await entered.promise
|
||||
let commands = 0
|
||||
const operation = gate.exclusive(async () => { commands++ })
|
||||
await assert.rejects(gate.request(async () => {}), /повторите запрос позже/)
|
||||
await assert.rejects(gate.exclusive(async () => {}), /уже выполняется/)
|
||||
assert.equal(commands, 0)
|
||||
pending.resolve(); await request; await operation
|
||||
assert.equal(commands, 1)
|
||||
await gate.request(async () => {})
|
||||
})
|
||||
|
||||
test("drain timeout cancels command without declaring an active handler finished", async () => {
|
||||
const gate = new DatabaseRequestGate(), pending = deferred()
|
||||
const request = gate.request(() => pending.promise)
|
||||
let commands = 0
|
||||
await assert.rejects(gate.exclusive(async () => { commands++ }, 10), /операция с базой отменена/)
|
||||
assert.equal(commands, 0)
|
||||
const retry = gate.exclusive(async () => { commands++ })
|
||||
await Promise.resolve(); assert.equal(commands, 0)
|
||||
pending.resolve(); await request; await retry
|
||||
assert.equal(commands, 1)
|
||||
})
|
||||
|
||||
test("stream cancellation waits for its asynchronous cleanup", async () => {
|
||||
const gate = new DatabaseRequestGate(), aborted = deferred(), cleanup = deferred()
|
||||
const stream = gate.request(async () => { await aborted.promise; await cleanup.promise }, aborted.resolve)
|
||||
let commands = 0
|
||||
const operation = gate.exclusive(async () => { commands++ })
|
||||
await aborted.promise; assert.equal(commands, 0)
|
||||
cleanup.resolve(); await stream; await operation; assert.equal(commands, 1)
|
||||
})
|
||||
|
||||
test("Fastify gate covers GET, keeps health available and drains late stream registration", async () => {
|
||||
const app = Fastify(); installDatabaseRequestGate(app)
|
||||
const entered = deferred(), read = deferred(), cleanup = deferred(), command = deferred(), leave = deferred()
|
||||
app.get('/health', async () => ({ ok: true }))
|
||||
await app.register(async child => {
|
||||
child.get('/traffic/flow/live', async request => {
|
||||
entered.resolve(); await read.promise
|
||||
const aborted = deferred(); registerDatabaseStreamAbort(request, aborted.resolve)
|
||||
await aborted.promise; await cleanup.promise
|
||||
return { closed: true }
|
||||
})
|
||||
child.get('/servers', async () => ({ servers: [] }))
|
||||
child.post('/system/database/restore', async () => { command.resolve(); await leave.promise; return { ok: true } })
|
||||
}, { prefix: '/api' })
|
||||
try {
|
||||
const stream = app.inject('/api/traffic/flow/live'); await entered.promise
|
||||
const operation = app.inject({ method: 'POST', url: '/api/system/database/restore' })
|
||||
// inject schedules asynchronously: wait for gate to reject a subsequent GET.
|
||||
await new Promise(r => setTimeout(r, 10))
|
||||
assert.equal((await app.inject('/api/servers')).statusCode, 409)
|
||||
assert.equal((await app.inject('/health')).statusCode, 200)
|
||||
read.resolve(); cleanup.resolve(); await stream; await command.promise
|
||||
assert.equal((await app.inject({ method: 'POST', url: '/api/system/database/restore' })).statusCode, 409)
|
||||
leave.resolve(); assert.equal((await operation).statusCode, 200)
|
||||
assert.equal((await app.inject('/api/servers')).statusCode, 200)
|
||||
} finally { read.resolve(); cleanup.resolve(); leave.resolve(); await app.close() }
|
||||
})
|
||||
@@ -0,0 +1,39 @@
|
||||
function conflict(message: string): Error & { statusCode: number } {
|
||||
return Object.assign(new Error(message), { statusCode: 409 })
|
||||
}
|
||||
|
||||
/** Handler lifetime, not socket lifetime: disconnect does not finish an active write. */
|
||||
export class DatabaseRequestGate {
|
||||
private paused = false
|
||||
private active = new Map<symbol, (() => void) | undefined>()
|
||||
private idle: (() => void) | undefined
|
||||
|
||||
async request<T>(run: () => Promise<T>, cancelStream?: () => void): Promise<T> {
|
||||
if (this.paused) throw conflict("Выполняется операция с базой приложения; повторите запрос позже")
|
||||
const lease = Symbol()
|
||||
this.active.set(lease, cancelStream)
|
||||
try { return await run() }
|
||||
finally {
|
||||
this.active.delete(lease)
|
||||
if (!this.active.size) this.idle?.()
|
||||
}
|
||||
}
|
||||
|
||||
async exclusive<T>(run: () => Promise<T>, timeoutMs = 30_000): Promise<T> {
|
||||
if (this.paused) throw conflict("Операция с базой приложения уже выполняется")
|
||||
this.paused = true
|
||||
let timer: ReturnType<typeof setTimeout> | undefined
|
||||
try {
|
||||
for (const cancel of this.active.values()) cancel?.()
|
||||
if (this.active.size) await new Promise<void>((resolve, reject) => {
|
||||
this.idle = resolve
|
||||
timer = setTimeout(() => reject(conflict("Не удалось дождаться завершения API-запросов; операция с базой отменена")), timeoutMs)
|
||||
})
|
||||
return await run()
|
||||
} finally {
|
||||
if (timer) clearTimeout(timer)
|
||||
this.idle = undefined
|
||||
this.paused = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
Приложение использует pg_dump -Fc и pg_restore --single-transaction --clean --if-exists. Транзакционный режим описан в [документации PostgreSQL](https://www.postgresql.org/docs/current/app-pgrestore.html). Проверка пяти байтов PGDMP проверяет заголовок, но не полноту и не доверие к архиву. Для rollback нужен сценарий с ошибкой исполнения restore, а не только отказ HTTP до его начала.
|
||||
|
||||
В локальном блоке12.5.8 добавлено ожидание текущих scheduler jobs с закрытием admission, но этот код ещё не развёрнут на стенде673e5ba. Блок12.5.9 добавляет отдельный graceful shutdown worker для database operation, serial flush, pool.end и обязательные acknowledgement/exit0. Локальные protocol tests и настоящий isolated collector/UDP/blocked SQL drain12.5.10 прошли: [evidence](ux-ui/acceptance/netflow-worker-2026-10-07.json). Основной код на стенде ещё не обновлён; app-wide quiescence этим не подтверждена. Ручные API writers, вспомогательные writers и экземпляры на других хостах также требуют отдельного контроля. PG-6 остаётся открытым до наблюдаемого подтверждения; восстановление стенда выполняется после его получения. Реальные тесты backend, способные очищать таблицы, запускаются только против выделенной тестовой БД.
|
||||
В локальном блоке12.5.8 добавлено ожидание текущих scheduler jobs с закрытием admission, но этот код ещё не развёрнут на стенде673e5ba. Блок12.5.9 добавляет отдельный graceful shutdown worker для database operation, serial flush, pool.end и обязательные acknowledgement/exit0. Локальные protocol tests и настоящий isolated collector/UDP/blocked SQL drain12.5.10 прошли: [evidence](ux-ui/acceptance/netflow-worker-2026-10-07.json). Основной код на стенде ещё не обновлён; app-wide quiescence этим не подтверждена. Блок12.5.11 локально добавляет admission/drain всех API handlers иtraffic live streams; новые tests/build passed, на стенде patch не развёрнут. Detached backup jobs/audit иRIPE background persistence ещё неохвачены и требуют12.5.12. Другие экземпляры/хосты требуют отдельного контроля. PG-6 остаётся открытым до наблюдаемого подтверждения; восстановление стенда выполняется после его получения. Реальные тесты backend, способные очищать таблицы, запускаются только против выделенной тестовой БД.
|
||||
|
||||
После bootstrap достаточно следующих запросов чтения для начальной проверки, без вывода секретов:
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# План реализации UX/UI по пятичасовым окнам
|
||||
|
||||
Актуальное продолжение 2026-10-07:12.5.10 завершён в границах настоящего isolated NetFlow collector: UDP→SQL, ожидание blocked write, освобождение socket до drain, ack/exit0, delta1500bytes и0worker connections подтверждены. Основной runtime остаётся673e5ba. Следующий12.5.11 — admission/drain ручных API и аудит вспомогательных writers перед restore. PG-6 целиком ещё открыт.
|
||||
Актуальное продолжение 2026-10-07:12.5.11 завершён локально для HTTP handlers — backup/restore закрывают API admission, ждут завершения обработчиков и останавливают traffic live-подписки с ожиданиемcleanup. Четыре новых теста,15lifecycle/database tests,HTTP/JWT scripts иbuild passed. Основной runtime673e5ba не обновлён. Следующий12.5.12 — detached backup jobs/audit иRIPE persistence; PG-6/restore остаются открытыми.
|
||||
|
||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-07. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||
|
||||
|
||||
+13
-1
@@ -1,6 +1,6 @@
|
||||
# UX/UI: журнал реализации
|
||||
|
||||
Актуальное продолжение 2026-10-07:12.5.10 завершён в границах настоящего isolated NetFlow collector: UDP→SQL, ожидание blocked write, освобождение socket до drain, ack/exit0, delta1500bytes и0worker connections подтверждены. Основной runtime остаётся673e5ba. Следующий12.5.11 — admission/drain ручных API и аудит вспомогательных writers перед restore. PG-6 целиком ещё открыт.
|
||||
Актуальное продолжение 2026-10-07:12.5.11 завершён локально для HTTP handlers — backup/restore закрывают API admission, ждут завершения обработчиков и останавливают traffic live-подписки с ожиданиемcleanup. Четыре новых теста,15lifecycle/database tests,HTTP/JWT scripts иbuild passed. Основной runtime673e5ba не обновлён. Следующий12.5.12 — detached backup jobs/audit иRIPE persistence; PG-6/restore остаются открытыми.
|
||||
|
||||
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
||||
|
||||
@@ -34,6 +34,18 @@
|
||||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в описанных границах:12.3.83,main1186/1186,context221/221. Этап остаётся в работе: стенд12.5.1–3 развёрнут,bootstrap/smoke проверены;остальные сценарии12.5 не выполнены. |
|
||||
|
||||
## 12.5.11 — ожидание ручных API-запросов и закрытие live-подписок (2026-10-07)
|
||||
|
||||
Добавлен DatabaseRequestGate и root onRoute hook перед регистрацией API. Каждый API handler получает lease до выполнения и освобождает его вfinally после фактического завершения, а не onResponse/socket close. ВключеныGET: некоторые чтения имеют lazy/cache side effects. /health и /api/auth/config остаются доступными. Backup/restore захватывают exclusive gate на весь handler, включая audit event; новый API-запрос получает409 с понятной причиной, конкурирующая database operation409. Ожидание30сек; timeout отменяет команду, не объявляет незавершённые запросы завершёнными; при повторной попытке они остаются в active registry.
|
||||
|
||||
Traffic flow live и server traffic live регистрируют abort callback. Exclusive gate останавливает их циклы и ждёт завершения asynchronous cleanup; не подменяет закрытие socket завершением обработчика. Отмена запоминается и приходит сразу при поздней регистрации callback, если ещё выполнялось первоначальное чтение сервера. Прочие длительные запросы не прерываются принудительно: при превышении30сек database operation отменяется. Gate локален одному Fastify instance; другие процессы/экземпляры не охвачены.
|
||||
|
||||
Аудит выявил detached writers: routes/backups.ts запускает event promise иqueueMicrotask/processBackupJob послеHTTP202; traffic-flow-ripe.ts запускает background resolver/loadPg и fire-and-forget persist/persistAsn. HTTP lease эти задачи не покрывает. Их нельзя считать завершёнными только поHTTP-ответу; PG-6 остаётся открытым, API restore не выполнялся. Код на сервере не пересобирался/не развёртывался, основной source673e5ba сохраняется.
|
||||
|
||||
Проверки:4новых gate tests passed — ожидание активного handler/отказ новых иконкурирующегоexclusive, timeout с нулёмdatabase commands иправильнымповторнымdrain, stream cancellation сожиданиемcleanup, Fastify child routes/GET409/health200/поздняярегистрацияabort/возобновлениеAPI. Полный test:system-database15pure/protocol tests иHTTP/JWT scripts passed; contracts/backend build passed; diff-check passed. Новые проверки включены вpackage script. Изменены index.ts, traffic.ts, traffic-flow.ts, добавлены gate service/plugin/test. RouterOS иданныестенда не менялись.
|
||||
|
||||
Следующий12.5.12 — зарегистрировать/дождаться detached backup jobs иaudit, закрыть admission идождатьсяRIPE resolver/persistence; послеэтого сборка/развёртывание ивнешняяPG-6/PG-3/4 проверка. Локальныйкоммит безpush.
|
||||
|
||||
## 12.5.10 — настоящий NetFlow collector: UDP и ожидание SQL перед выходом (2026-10-07)
|
||||
|
||||
На161.104.46.222 запущен временный docker compose run --rm --no-deps backend с актуальным compiled dist изsourcef8da3e0; основной backend/frontend не пересоздавались. DATABASE_URL в памяти тестового процесса/унаследованного worker ограничен отдельной mmapp_acceptance_20261007. Приложение не подключено к этой БД. [Очищенный отчёт](ux-ui/acceptance/netflow-worker-2026-10-07.json), SHA256 архива и worker JS совпали с локальными файлами. Секреты/дампы не передавались в репозиторий.
|
||||
|
||||
+13
-1
@@ -1,6 +1,6 @@
|
||||
# Этап 12: итоговая приёмка UX/UI
|
||||
|
||||
Актуальное продолжение 2026-10-07:12.5.10 завершён в границах настоящего isolated NetFlow collector: UDP→SQL, ожидание blocked write, освобождение socket до drain, ack/exit0, delta1500bytes и0worker connections подтверждены. Основной runtime остаётся673e5ba. Следующий12.5.11 — admission/drain ручных API и аудит вспомогательных writers перед restore. PG-6 целиком ещё открыт.
|
||||
Актуальное продолжение 2026-10-07:12.5.11 завершён локально для HTTP handlers — backup/restore закрывают API admission, ждут завершения обработчиков и останавливают traffic live-подписки с ожиданиемcleanup. Четыре новых теста,15lifecycle/database tests,HTTP/JWT scripts иbuild passed. Основной runtime673e5ba не обновлён. Следующий12.5.12 — detached backup jobs/audit иRIPE persistence; PG-6/restore остаются открытыми.
|
||||
|
||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||
|
||||
@@ -1042,3 +1042,15 @@ PG-6 ещё открыт: тест с реальным collector/UDP и длит
|
||||
Проверочная БД теперь содержит синтетические flow rows и изменённые collector counters; прежнее сравнение12.5.7 описывает состояние на момент backup, не нынешнюю идентичность БД. Временный контейнер удалён штатным--rm, worker остановлен. Основной /health ok/version1.0.0-test.673e5ba/alivefalse/boundfalse, оба serverID/IP иuptime retention14 сохранены. КонфигурацияCHR/traffic-flow на маршрутизаторах не менялась.
|
||||
|
||||
Принята частьPG-6 для isolated collector/drain, не весь app-wide сценарий. Ручные API writers, вспомогательные writers, параллельные экземпляры и API restore не проверены; новый код ещё не развёрнут в основном приложении. Следующий12.5.11 — admission/drain ручных запросов и аудит остальных писателей, затем deployment и полнаяPG-6/PG-3/4 проверка. Локальный коммит безpush.
|
||||
|
||||
## 12.5.11 — ожидание ручных API-запросов и закрытие live-подписок (2026-10-07)
|
||||
|
||||
Добавлен DatabaseRequestGate и root onRoute hook перед регистрацией API. Каждый API handler получает lease до выполнения и освобождает его вfinally после фактического завершения, а не onResponse/socket close. ВключеныGET: некоторые чтения имеют lazy/cache side effects. /health и /api/auth/config остаются доступными. Backup/restore захватывают exclusive gate на весь handler, включая audit event; новый API-запрос получает409 с понятной причиной, конкурирующая database operation409. Ожидание30сек; timeout отменяет команду, не объявляет незавершённые запросы завершёнными; при повторной попытке они остаются в active registry.
|
||||
|
||||
Traffic flow live и server traffic live регистрируют abort callback. Exclusive gate останавливает их циклы и ждёт завершения asynchronous cleanup; не подменяет закрытие socket завершением обработчика. Отмена запоминается и приходит сразу при поздней регистрации callback, если ещё выполнялось первоначальное чтение сервера. Прочие длительные запросы не прерываются принудительно: при превышении30сек database operation отменяется. Gate локален одному Fastify instance; другие процессы/экземпляры не охвачены.
|
||||
|
||||
Аудит выявил detached writers: routes/backups.ts запускает event promise иqueueMicrotask/processBackupJob послеHTTP202; traffic-flow-ripe.ts запускает background resolver/loadPg и fire-and-forget persist/persistAsn. HTTP lease эти задачи не покрывает. Их нельзя считать завершёнными только поHTTP-ответу; PG-6 остаётся открытым, API restore не выполнялся. Код на сервере не пересобирался/не развёртывался, основной source673e5ba сохраняется.
|
||||
|
||||
Проверки:4новых gate tests passed — ожидание активного handler/отказ новых иконкурирующегоexclusive, timeout с нулёмdatabase commands иправильнымповторнымdrain, stream cancellation сожиданиемcleanup, Fastify child routes/GET409/health200/поздняярегистрацияabort/возобновлениеAPI. Полный test:system-database15pure/protocol tests иHTTP/JWT scripts passed; contracts/backend build passed; diff-check passed. Новые проверки включены вpackage script. Изменены index.ts, traffic.ts, traffic-flow.ts, добавлены gate service/plugin/test. RouterOS иданныестенда не менялись.
|
||||
|
||||
Следующий12.5.12 — зарегистрировать/дождаться detached backup jobs иaudit, закрыть admission идождатьсяRIPE resolver/persistence; послеэтого сборка/развёртывание ивнешняяPG-6/PG-3/4 проверка. Локальныйкоммит безpush.
|
||||
@@ -85,3 +85,7 @@ ssh -N -L 3000:127.0.0.1:3000 -L 8000:127.0.0.1:8000 root@161.104.46.222
|
||||
## Настоящий isolated collector — 2026-10-07
|
||||
|
||||
[12.5.10 evidence](ux-ui/acceptance/netflow-worker-2026-10-07.json): актуальныйworker изf8da3e0 в отдельном временном контейнере, выделеннаяmmapp_acceptance_20261007, UDP4749 только внутриконтейнера. Shutdown дождался blocked SQL/освободилsocket, ack+exit0, delta1500bytes,0worker connections. Контейнер удалён--rm. ПроверочнаяБД теперь содержит синтетические flow rows/counters; архив12.5.7 остаётся исходным snapshot. Основной runtime673e5ba/healthok/serverID1–2/retention14 сохранён. App-wide PG-6/ручные API writers/restore ещё открыты; следующий12.5.11 — аудит и admission остальных писателей.
|
||||
|
||||
## Локальный HTTP drain patch — 2026-10-07
|
||||
|
||||
12.5.11 добавляет instance-local gate для всех API handlers/GET, exclusive backup/restore иabort/drain traffic live streams.4gate tests,15lifecycle/database tests,HTTP/JWT scripts иbuild passed. Основнойruntime673e5ba остаётсяактивным. Detached backup jobs/audit иRIPE persistence ещёнеохвачены; следующий12.5.12 закрываетэтотпробел. PG-6/restore не приняты.
|
||||
Reference in new issue
Block a user