fix(proxmox): vorübergehende Störungen wiederholen statt abbrechen
Der Feldtest auf einem ausgelasteten pve-demo scheiterte an Verbindungswacklern, nicht an Proxmox: pveproxy meldete „Broken pipe“ (Backend weg), schloss Keep-Alive-Verbindungen, Storage-Abfragen dauerten 15 s. GET wird bis zu dreimal wiederholt, Schreibendes nur bei sicher nicht angekommener Anfrage; Schreibaufrufe dürfen 120 s dauern, Keep-Alive 2 s. Refs #020 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,15 +8,22 @@ import { MOCK_TOKEN_GEHEIMNIS, MOCK_TOKEN_ID, ProxmoxMock } from "../proxmox-moc
|
||||
|
||||
const mock = new ProxmoxMock();
|
||||
|
||||
function client(ueberschreiben: Partial<ConstructorParameters<typeof ProxmoxClient>[0]> = {}) {
|
||||
return new ProxmoxClient({
|
||||
url: mock.url,
|
||||
tokenId: MOCK_TOKEN_ID,
|
||||
tokenGeheimnis: MOCK_TOKEN_GEHEIMNIS,
|
||||
tlsPruefen: false,
|
||||
fingerabdruck: mock.fingerabdruck,
|
||||
...ueberschreiben,
|
||||
});
|
||||
function client(
|
||||
ueberschreiben: Partial<ConstructorParameters<typeof ProxmoxClient>[0]> = {},
|
||||
optionen: ConstructorParameters<typeof ProxmoxClient>[1] = {},
|
||||
) {
|
||||
return new ProxmoxClient(
|
||||
{
|
||||
url: mock.url,
|
||||
tokenId: MOCK_TOKEN_ID,
|
||||
tokenGeheimnis: MOCK_TOKEN_GEHEIMNIS,
|
||||
tlsPruefen: false,
|
||||
fingerabdruck: mock.fingerabdruck,
|
||||
...ueberschreiben,
|
||||
},
|
||||
// Ohne Pausen: Wiederholungen sollen Tests nicht ausbremsen.
|
||||
{ pauseMs: () => 0, ...optionen },
|
||||
);
|
||||
}
|
||||
|
||||
async function fehlerVon(versprechen: Promise<unknown>): Promise<ProxmoxFehler> {
|
||||
@@ -174,6 +181,58 @@ describe("ProxmoxClient", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Vorübergehende Störungen", () => {
|
||||
it("wiederholt GET nach „Broken pipe“ (596) und getrennter Verbindung und meldet es dem Beobachter", async () => {
|
||||
let n = 0;
|
||||
mock.route("GET", "/nodes/pve01/storage", () => {
|
||||
n += 1;
|
||||
if (n === 1) return { status: 596, statusText: "Broken pipe" };
|
||||
if (n === 2) return { trennen: true };
|
||||
return { data: [{ storage: "local" }] };
|
||||
});
|
||||
const gesehen: Array<{ fehler?: string; wiederholung?: number }> = [];
|
||||
const c = client(
|
||||
{},
|
||||
{ beobachter: (_a, e) => gesehen.push({ fehler: e.fehler?.ursache, wiederholung: e.wiederholung }) },
|
||||
);
|
||||
expect(await c.get("/nodes/pve01/storage")).toEqual([{ storage: "local" }]);
|
||||
expect(n).toBe(3);
|
||||
expect(gesehen.map((g) => g.wiederholung)).toEqual([1, 2, undefined]);
|
||||
expect(gesehen[0]!.fehler).toBe("Broken pipe");
|
||||
});
|
||||
|
||||
it("gibt nach drei Versuchen auf", async () => {
|
||||
let n = 0;
|
||||
mock.route("GET", "/nodes/pve02/storage", () => {
|
||||
n += 1;
|
||||
return { status: 596, statusText: "Broken pipe" };
|
||||
});
|
||||
const fehler = await fehlerVon(client().get("/nodes/pve02/storage"));
|
||||
expect(fehler.ursache).toBe("Broken pipe");
|
||||
expect(n).toBe(3);
|
||||
});
|
||||
|
||||
it("wiederholt Schreibendes nicht, wenn die Anfrage den Node erreicht haben kann", async () => {
|
||||
let n = 0;
|
||||
mock.route("POST", "/nodes/pve01/qemu", () => {
|
||||
n += 1;
|
||||
return n === 1 ? { trennen: true } : { data: "UPID:pve01:1:2:3:qmcreate:100:x:" };
|
||||
});
|
||||
await expect(client().post("/nodes/pve01/qemu", { vmid: 100 })).rejects.toThrow();
|
||||
expect(n).toBe(1);
|
||||
});
|
||||
|
||||
it("wiederholt keine fachlichen Fehler (500 mit Proxmox-Meldung, 403, 501)", async () => {
|
||||
let n = 0;
|
||||
mock.route("GET", "/nodes/pve03/storage", () => {
|
||||
n += 1;
|
||||
return { status: 500, statusText: "storage 'x' does not exist" };
|
||||
});
|
||||
await fehlerVon(client().get("/nodes/pve03/storage"));
|
||||
expect(n).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Proxmox-Tasks (UPID)", () => {
|
||||
const UPID = "UPID:pve01:0000A1B2:00C3D4E5:6710F00D:qmclone:9013:proxdeploy@pve!test:";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user