fix(api): дождаться фоновых записей перед операцией с БД
This commit is contained in:
1 parent
8682f2a7a5
commit
2943032462
18 files changed
+183
-29
No files matched your search
@@ -0,0 +1,62 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { test } from "node:test"
|
||||
import { DatabaseBackgroundWork, databaseBackgroundWork } from "./database-background-work.js"
|
||||
import Fastify from "fastify"
|
||||
import { validatorCompiler, serializerCompiler } from "@fastify/type-provider-zod"
|
||||
import { createBackupsRoutes } from "../routes/backups.js"
|
||||
|
||||
function deferred() {
|
||||
let resolve!: () => void
|
||||
const promise = new Promise<void>(r => { resolve = r })
|
||||
return { promise, resolve }
|
||||
}
|
||||
|
||||
test("drain includes writes scheduled by a task after its HTTP response", async () => {
|
||||
const work = new DatabaseBackgroundWork(), parent = deferred(), child = deferred()
|
||||
work.track(parent.promise.then(() => { work.track(child.promise) }))
|
||||
let finished = false
|
||||
const drain = work.drain().then(() => { finished = true })
|
||||
parent.resolve(); await parent.promise; await Promise.resolve()
|
||||
assert.equal(finished, false)
|
||||
child.resolve(); await drain; assert.equal(finished, true)
|
||||
})
|
||||
|
||||
test("timeout preserves pending tasks for the next attempt", async () => {
|
||||
const work = new DatabaseBackgroundWork(), pending = deferred()
|
||||
work.track(pending.promise)
|
||||
await assert.rejects(work.drain(10), /операция с базой отменена/)
|
||||
let finished = false
|
||||
const retry = work.drain().then(() => { finished = true })
|
||||
await Promise.resolve(); assert.equal(finished, false)
|
||||
pending.resolve(); await retry; assert.equal(finished, true)
|
||||
})
|
||||
|
||||
test("a task rejection is observed without breaking subsequent drain", async () => {
|
||||
const work = new DatabaseBackgroundWork()
|
||||
const task = work.track(Promise.reject(Error("audit failed")))
|
||||
await assert.rejects(task, /audit failed/)
|
||||
await work.drain()
|
||||
work.track(Promise.resolve()); await work.drain()
|
||||
})
|
||||
|
||||
test("real backup HTTP202 keeps its detached job registered through completion", async () => {
|
||||
const pending = deferred(), started = deferred()
|
||||
const app = Fastify(); app.setValidatorCompiler(validatorCompiler); app.setSerializerCompiler(serializerCompiler)
|
||||
await app.register(createBackupsRoutes({
|
||||
listServers: async () => [{ id: 1 }],
|
||||
appendEvent: async () => undefined as never,
|
||||
create: async () => {
|
||||
started.resolve(); await pending.promise
|
||||
return { id: "drain-backup", serverId: 1, serverName: "router", filename: "test.rsc", sizeBytes: 0,
|
||||
createdAt: "2026-10-07T00:00:00Z", kind: "manual", storage: "local" }
|
||||
},
|
||||
}), { prefix: "/api" })
|
||||
try {
|
||||
assert.equal((await app.inject({ method: "POST", url: "/api/backups/create", payload: { serverIds: [1] } })).statusCode, 202)
|
||||
await started.promise
|
||||
let finished = false
|
||||
const drain = databaseBackgroundWork.drain().then(() => { finished = true })
|
||||
await Promise.resolve(); assert.equal(finished, false)
|
||||
pending.resolve(); await drain; assert.equal(finished, true)
|
||||
} finally { pending.resolve(); await databaseBackgroundWork.drain(); await app.close() }
|
||||
})
|
||||
Reference in new issue
Block a user