fix(ui): сбрасывать снимок при изменении параметров speed-пробы

This commit is contained in:
Denozordec committed 2026-10-07 17:41:14 +07:00
1 parent 090206c893
commit 7f18fcb6db
11 files changed
+106 -22

No files matched your search

@@ -36,7 +36,15 @@ const saved = await put({ probes: [probe] }); assert.equal(saved.statusCode, 200
assert.equal(rows.has("old"), false); assert.equal(rows.get("s1")?.enabled, false); assert.equal(rows.get("s1")?.srcInterface, "ether1")
rows.get("s1")!.lastTxAvgMbps = 42
await put({ probes: [{ ...probe, durationSec: 20, lastTxAvgMbps: 0 }] })
assert.equal(rows.get("s1")?.lastTxAvgMbps, 42); assert.equal(rows.get("s1")?.durationSec, 20)
assert.equal(rows.get("s1")?.lastTxAvgMbps, null); assert.equal(rows.get("s1")?.durationSec, 20)
for (const edit of [{ srcInterface: "ether3" }, { dstInterface: "ether3" }, { protocol: "udp" }, { direction: "receive" }]) {
rows.get("s1")!.lastTxAvgMbps = 42
await put({ probes: [{ ...probe, ...edit }] })
assert.equal(rows.get("s1")?.lastTxAvgMbps, null)
rows.get("s1")!.lastTxAvgMbps = 0
await put({ probes: [{ ...probe, ...edit, enabled: true }] })
assert.equal(rows.get("s1")?.lastTxAvgMbps, 0)
}
const beforePairChange = rows.get("s1")!.srcServerId
await put({ probes: [{ ...probe, srcServerId: 2, dstServerId: 1 }] })
assert.notEqual(rows.get("s1")?.srcServerId, beforePairChange)
+1 -1
View File
@@ -208,7 +208,7 @@ const uptimeRoutes: FastifyPluginAsyncZod = async (app) => {
// Serialize complete replacements from all backend processes, including an empty catalog.
await tx.execute(sql`select pg_advisory_xact_lock(hashtext('uptime-speed-probes'))`)
await run({
listProbes: async () => tx.select({ id: uptimeSpeedProbes.id, srcServerId: uptimeSpeedProbes.srcServerId, dstServerId: uptimeSpeedProbes.dstServerId }).from(uptimeSpeedProbes).for("update"),
listProbes: async () => tx.select().from(uptimeSpeedProbes).for("update"),
remove: async id => { await tx.delete(uptimeSpeedProbes).where(eq(uptimeSpeedProbes.id, id)) },
upsert: async (row, createdAt, resetObservations) => {
const { id, ...patch } = row
@@ -1,20 +1,21 @@
import { matchesSpeedProbeEndpoints, type SpeedProbeEndpoints } from "./speed-run-persistence.js"
import { sameSpeedMeasurement } from "@mmapp/contracts"
import type { SpeedProbeWrite } from "@mmapp/contracts"
export type SpeedProbePatch = SpeedProbeWrite & { sortOrder: number; updatedAt: string }
export type SpeedProbeTransaction = {
listProbes: () => Promise<SpeedProbeEndpoints[]>
listProbes: () => Promise<SpeedProbeWrite[]>
remove: (id: string) => Promise<void>
upsert: (row: SpeedProbePatch, createdAt: string, resetObservations: boolean) => Promise<void>
}
export type SpeedProbeStore = { transaction: (run: (tx: SpeedProbeTransaction) => Promise<void>) => Promise<void> }
/** The adapter must lock the catalog and commit all configuration changes atomically. Observations are preserved for the same pair and reset when its endpoints change. */
/** The adapter must lock the catalog and commit all configuration changes atomically. Observations are preserved only for the same measurement parameters. */
export async function replaceSpeedProbes(store: SpeedProbeStore, probes: SpeedProbeWrite[], now = new Date().toISOString()): Promise<void> {
await store.transaction(async tx => {
const nextIds = new Set(probes.map(row => row.id))
const previous = new Map((await tx.listProbes()).map(row => [row.id, row]))
for (const id of previous.keys()) if (!nextIds.has(id)) await tx.remove(id)
for (const [sortOrder, row] of probes.entries()) {
const reset = !matchesSpeedProbeEndpoints(previous.get(row.id), row)
const old = previous.get(row.id)
const reset = !old || !sameSpeedMeasurement(old, row)
await tx.upsert({ ...row, sortOrder, updatedAt: now }, now, reset)
}
})