feat(db): перевести хранилище с SQLite на PostgreSQL
Docker images / prepare-release (push) Successful in 12s
Docker images / backend-test (push) Successful in 4m9s
Docker images / frontend-image (push) Successful in 4m28s
Docker images / updater-image (push) Successful in 58s
Docker images / backend-image (push) Successful in 2m49s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 11s

При старте backend накатывает схему PostgreSQL 18 и, если база пустая, один раз импортирует mikrotik.db с тома. Повторный старт не копирует данные. Бэкап в UI идёт через pg_dump.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-08 01:36:48 +07:00
co-authored by Cursor
parent 0e5fb065e2
commit ec43591a99
128 changed files with 4304 additions and 3639 deletions
+13 -11
View File
@@ -1,5 +1,6 @@
import { eq } from "drizzle-orm"
import { db } from "../db/index.js"
import { eq, lt } from "drizzle-orm"
import { db, pool } from "../db/index.js"
import { dropExpiredPartitions, ensurePartitionsAround } from "../db/partitions.js"
import { servers, serverSnapshots } from "../db/schema.js"
import type { SnapshotInsert } from "../db/schema.js"
import type { SnapshotRead } from "../types/server.js"
@@ -14,12 +15,11 @@ import { invalidateFlowCatalogCache } from "./traffic-flow-topology.js"
* and sync the server's display name from system/identity.
*/
export async function pollServer(serverId: number): Promise<SnapshotRead> {
const server = db
const server = (await db
.select()
.from(servers)
.where(eq(servers.id, serverId))
.limit(1)
.all()[0]
.limit(1))[0]
if (!server) {
throw new Error(`Server with id=${serverId} not found`)
@@ -61,15 +61,14 @@ export async function pollServer(serverId: number): Promise<SnapshotRead> {
cpuLoad,
freeMemory: freeMem,
totalMemory: totalMem,
rawInterfaces: JSON.stringify(ifaces),
rawIpAddresses: JSON.stringify(addresses),
rawInterfaces: ifaces,
rawIpAddresses: addresses,
} satisfies Partial<SnapshotInsert>)
if ((identity.name || "") !== (server.name || "")) {
db.update(servers)
await db.update(servers)
.set({ name: identity.name, updatedAt: now })
.where(eq(servers.id, serverId))
.run()
invalidateFlowCatalogCache()
}
@@ -78,11 +77,14 @@ export async function pollServer(serverId: number): Promise<SnapshotRead> {
console.warn(`[poller] server id=${serverId} unreachable:`, (err as Error).message)
}
const [inserted] = db
const [inserted] = await db
.insert(serverSnapshots)
.values(partialSnap as SnapshotInsert)
.returning()
.all()
const cutoffIso = new Date(Date.now() - 14 * 24 * 3600_000).toISOString()
await db.delete(serverSnapshots).where(lt(serverSnapshots.polledAt, cutoffIso))
void dropExpiredPartitions(pool).then(() => ensurePartitionsAround(pool))
return toSnapshotRead(inserted)
}