feat(auftraege): worker, Phasen und Live-Fortschritt per SSE

Aufträge laufen als pg-boss-Jobs im worker. Der Phasen-Runner der Engine
kennt weder Proxmox noch Datenbank; eine Senke schreibt Phasen und Log
in die DB und meldet per NOTIFY, die app streamt per SSE an Web und CLI
(Last-Event-ID, Herzschlag, Polling-Fallback im Browser).

VMIDs vergibt eine Advisory-Sperre je Server zusammen mit einer
Reservierungstabelle; zehn parallele Reservierungen im Test bekommen
zehn verschiedene IDs. Der Proxmox-Client hat einen Trockenmodus für
den Dry-Run: Lesendes echt, Schreibendes nur aufgezeichnet.

Live-Ansicht im Aufbau der CLI-Ausgabe. Im echten Betrieb aufgefallen:
ssh2 und pg sind CommonJS und brauchen im worker Default-Importe.

Closes #006

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 10:54:41 +02:00
co-authored by Claude Opus 5.5
parent 01d22aac3a
commit 76bc0e4269
38 changed files with 2274 additions and 22 deletions
+20
View File
@@ -0,0 +1,20 @@
import type { EreignisSenke } from "@/engine/ablauf/ablauf";
import type { AufrufBeobachter } from "@/engine/proxmox/client";
/**
* Schreibt Proxmox-Aufrufe ins Detail-Log. Die Abfrageschleifen (Task-Status, Task-Log,
* VM-Status) erscheinen nur bei Fehlern – sonst stünden bei jedem Download Hunderte gleicher
* Zeilen da, und das Wichtige ginge unter.
*/
const SCHLEIFE = /\/tasks\/[^/]+\/(status|log)$|\/status\/current$/;
export function aufrufLogger(senke: EreignisSenke): AufrufBeobachter {
return (aufruf, ergebnis) => {
const pfad = decodeURIComponent(aufruf.pfad);
if (!ergebnis.fehler && aufruf.methode === "GET" && SCHLEIFE.test(pfad)) return;
void senke.log(
ergebnis.fehler ? "warn" : "debug",
`${aufruf.methode} ${pfad} · ${ergebnis.dauerMs} ms${ergebnis.fehler ? ` · ${ergebnis.fehler.ursache}` : ""}`,
);
};
}