fix(backups): не повторять импорт после потери ответа
This commit is contained in:
1 parent
99ff5aebaf
commit
39570656c9
10 files changed
+63
-8
No files matched your search
@@ -0,0 +1,24 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { test } from "node:test"
|
||||
import { MikrotikClient, MikrotikError } from "./mikrotik.js"
|
||||
import { BackupRestoreUnknownError, importBackupOnce } from "./backup-restore.js"
|
||||
const makeClient = () => new MikrotikClient({ host: "router.invalid", port: 80, useSsl: false, verifySsl: false, username: "test", password: "test" })
|
||||
test("import does not fallback after ambiguous failure or command rejection", async () => {
|
||||
for (const error of [new Error("connection lost after apply"), new Error("Invalid JSON"), new MikrotikError(500, "/import", "error"), new MikrotikError(400, "/import", "script failed"), new MikrotikError(401, "/import", "unauthorized")]) {
|
||||
const client = makeClient(), calls: string[] = []
|
||||
client.post = async <T>(endpoint: string): Promise<T> => { calls.push(endpoint); throw error }
|
||||
await assert.rejects(client.importUploadedFile("config.rsc"), error); assert.deepEqual(calls, ["/import"])
|
||||
}
|
||||
})
|
||||
test("unsupported endpoint retains one fallback and successful import is not repeated", async () => {
|
||||
for (const status of [200, 404, 405]) {
|
||||
const client = makeClient(), calls: string[] = []
|
||||
client.post = async <T>(endpoint: string): Promise<T> => { calls.push(endpoint); if (endpoint === "/import" && status !== 200) throw new MikrotikError(status, endpoint, "unsupported"); return { ok: true } as T }
|
||||
await client.importUploadedFile("config.rsc"); assert.deepEqual(calls, status === 200 ? ["/import"] : ["/import", "/execute"])
|
||||
}
|
||||
})
|
||||
test("failed import has unknown outcome and no application retry", async () => {
|
||||
let calls = 0
|
||||
await assert.rejects(importBackupOnce("config.rsc", async () => { calls++; throw new Error("lost response") }), BackupRestoreUnknownError)
|
||||
assert.equal(calls, 1); await importBackupOnce("config.rsc", async () => ({}))
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
export class BackupRestoreUnknownError extends Error {
|
||||
constructor(options?: ErrorOptions) { super("Результат импорта неизвестен. Проверьте конфигурацию роутера перед повтором.", options); this.name = "BackupRestoreUnknownError" }
|
||||
}
|
||||
export async function importBackupOnce(file: string, apply: (file: string) => Promise<unknown>): Promise<void> {
|
||||
try { await apply(file) } catch (cause) { throw new BackupRestoreUnknownError({ cause }) }
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import type {
|
||||
PutBackupStorageSettings,
|
||||
} from "@mmapp/contracts/backups"
|
||||
import { mapBackupEntry } from "./backup-dto.js"
|
||||
import { importBackupOnce } from "./backup-restore.js"
|
||||
import { deleteStoredBackup } from "./backup-deletion.js"
|
||||
import { planBackupStorageUpdate } from "./backup-storage-update.js"
|
||||
import { db } from "../db/index.js"
|
||||
@@ -477,7 +478,7 @@ export async function restoreBackupToDevice(id: string): Promise<{ backupId: str
|
||||
const content = await readBackupContent(meta)
|
||||
const client = MikrotikClient.fromServer(row)
|
||||
const uploaded = await client.uploadTextFile(meta.filename, content.toString("utf8"), 60_000)
|
||||
await client.importUploadedFile(uploaded)
|
||||
await importBackupOnce(uploaded, file => client.importUploadedFile(file))
|
||||
return { backupId: meta.id, serverId: row.id, filename: meta.filename, serverName: row.name }
|
||||
}
|
||||
|
||||
|
||||
@@ -784,7 +784,8 @@ export class MikrotikClient {
|
||||
async importUploadedFile(fileName: string): Promise<unknown> {
|
||||
try {
|
||||
return await this.post("/import", { "file-name": fileName }, 120_000)
|
||||
} catch {
|
||||
} catch (error) {
|
||||
if (!(error instanceof MikrotikError) || ![404, 405].includes(error.statusCode)) throw error
|
||||
return await this.post("/execute", { script: `/import file-name="${fileName}"` }, 120_000)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user