fix(api): сохранять каталог пинг-проб атомарно
This commit is contained in:
1 parent
9c22fa8a68
commit
53c1bfbd3b
15 files changed
+243
-122
No files matched your search
@@ -0,0 +1,21 @@
|
||||
import type { PingProbeWrite } from "@mmapp/contracts"
|
||||
export type PingProbePatch = Omit<PingProbeWrite, "filter"> & { probeFilter: string; sortOrder: number; updatedAt: string }
|
||||
export type PingProbeTransaction = {
|
||||
listIds: () => Promise<string[]>
|
||||
remove: (id: string) => Promise<void>
|
||||
upsert: (row: PingProbePatch, createdAt: string) => Promise<void>
|
||||
}
|
||||
export type PingProbeStore = { transaction: (run: (tx: PingProbeTransaction) => Promise<void>) => Promise<void> }
|
||||
export async function replacePingProbes(store: PingProbeStore, probes: PingProbeWrite[], now = new Date().toISOString()): Promise<void> {
|
||||
await store.transaction(async tx => {
|
||||
const nextIds = new Set(probes.map(row => row.id))
|
||||
for (const id of await tx.listIds()) if (!nextIds.has(id)) await tx.remove(id)
|
||||
for (const [sortOrder, row] of probes.entries()) {
|
||||
const { filter, intervalSec, showOnDashboard, ...config } = row
|
||||
await tx.upsert({ ...config, probeFilter: filter, sortOrder, updatedAt: now,
|
||||
...(intervalSec === undefined ? {} : { intervalSec: intervalSec > 0 ? Math.max(5, intervalSec) : 0 }),
|
||||
...(showOnDashboard === undefined ? {} : { showOnDashboard }),
|
||||
}, now)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { and, asc, eq, gte, inArray, max, or } from "drizzle-orm"
|
||||
import { replacePingProbes } from "./ping-probe-replacement.js"
|
||||
import type { PingProbeWrite } from "@mmapp/contracts"
|
||||
import { and, asc, eq, gte, inArray, max, or, sql } from "drizzle-orm"
|
||||
import { db } from "../db/index.js"
|
||||
import {
|
||||
servers,
|
||||
@@ -467,49 +469,19 @@ export async function updateProbeShowOnDashboard(probeId: string, showOnDashboar
|
||||
return r.length > 0
|
||||
}
|
||||
|
||||
export async function replaceProbes(rows: Array<{
|
||||
id: string
|
||||
srcServerId: number
|
||||
srcInterface: string
|
||||
name: string
|
||||
target: string
|
||||
probeFilter: string
|
||||
enabled: boolean
|
||||
showOnDashboard?: boolean
|
||||
intervalSec?: number
|
||||
}>) {
|
||||
const now = new Date().toISOString()
|
||||
const existing = await db.select({ id: uptimeProbes.id }).from(uptimeProbes)
|
||||
const nextIds = new Set(rows.map((r) => r.id))
|
||||
|
||||
for (const p of existing) {
|
||||
if (nextIds.has(p.id)) continue
|
||||
await db.delete(uptimeProbes).where(eq(uptimeProbes.id, p.id))
|
||||
}
|
||||
|
||||
for (let i = 0; i < rows.length; i += 1) {
|
||||
const r = rows[i]
|
||||
const intervalSec = r.intervalSec != null && r.intervalSec > 0 ? Math.max(5, Math.floor(r.intervalSec)) : 0
|
||||
const patch = {
|
||||
srcServerId: r.srcServerId,
|
||||
srcInterface: r.srcInterface || "",
|
||||
name: r.name,
|
||||
target: r.target,
|
||||
probeFilter: r.probeFilter || "—",
|
||||
enabled: r.enabled,
|
||||
showOnDashboard: r.showOnDashboard ?? false,
|
||||
intervalSec,
|
||||
sortOrder: i,
|
||||
updatedAt: now,
|
||||
}
|
||||
const updated = await db.update(uptimeProbes).set(patch).where(eq(uptimeProbes.id, r.id)).returning({ id: uptimeProbes.id })
|
||||
if (updated.length > 0) continue
|
||||
await db.insert(uptimeProbes).values({
|
||||
id: r.id,
|
||||
...patch,
|
||||
createdAt: now,
|
||||
export async function replaceProbes(rows: PingProbeWrite[]) {
|
||||
await replacePingProbes({ transaction: run => db.transaction(async tx => {
|
||||
await tx.execute(sql`select pg_advisory_xact_lock(hashtext('uptime-ping-probes'))`)
|
||||
await run({
|
||||
listIds: async () => (await tx.select({ id: uptimeProbes.id }).from(uptimeProbes)).map(row => row.id),
|
||||
remove: async id => { await tx.delete(uptimeProbes).where(eq(uptimeProbes.id, id)) },
|
||||
upsert: async (row, createdAt) => {
|
||||
const { id, ...patch } = row
|
||||
await tx.insert(uptimeProbes).values({ id, ...patch, createdAt })
|
||||
.onConflictDoUpdate({ target: uptimeProbes.id, set: patch })
|
||||
},
|
||||
})
|
||||
}
|
||||
}) }, rows)
|
||||
}
|
||||
|
||||
export async function readProbeSamplesSince(sinceIso: string) {
|
||||
|
||||
Reference in new issue
Block a user