From c98aa0655412268b681ddec46bfa9f23d53a4ee4 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Fri, 11 Sep 2026 14:36:09 +0200 Subject: [PATCH] pruef-agentur kann jetzt sagen, woran sie scheitert Sie meldete 31-mal "FEHL" und HTTP 503 -- und kein einziges Wort dazu, warum. Die Serverausgabe hat sie immer schon mitgeschrieben, aber nur gezeigt, wenn der Server gar nicht erst hochkam. Faellt er spaeter mit einem Datenbankfehler um, war sie weg. Dazu kam: Playwright wirft bei einem fehlenden Knopf eine Ausnahme, der Prozess stirbt, und mit ihm die Zusammenfassung. Genau dann braucht man sie am dringendsten. Deshalb haengt die Ausgabe jetzt auch an uncaughtException und unhandledRejection. Mit SERVERLOG= kommt das Protokoll vollstaendig heraus -- die letzten 1800 Zeichen zeigen den Schaden, nicht immer seine Ursache. Genau daran lag es hier: Der Verlust stand ganz oben, der Fehler ganz unten. WAS DAMIT IN EINEM LAUF SICHTBAR WURDE (Befund, noch nicht repariert): [workspace] Spalte 'einsatz' in eintraege ergaenzt. [workspace] Bereich 'agentur' freigeschaltet, 5 Eintraege [workspace] Bereich lesen: no such column: e.einsatz Die Spalte wird angelegt und unmittelbar danach wieder verworfen. Die einmalige 'agentur'-Umstellung baut `eintraege` mit einer FEST EINGETRAGENEN Spaltenliste neu -- 24 Spalten gehen hinein, 21 kommen heraus. Verloren gehen einsatz, nur_leitung und gesendet_am: die drei, die nach dem 07.09.2026 dazukamen. Der Kommentar an genau dieser Stelle warnt woertlich vor dieser Verlustart -- damals fuer die drei Event-Spalten, die deshalb nachgetragen wurden. Die Liste war am 07.09. richtig und ist seither still falsch geworden. Dieselbe feste Zahl, dieselbe Falle, drittes Mal. DIE ECHTEN DATEN SIND NICHT BETROFFEN, nachgemessen statt vermutet: Die Datenbank auf dem Server hat alle drei Spalten, und ihr CHECK kennt 'agentur' bereits -- die Umstellung laeuft dort nie wieder. Gefaehrlich wird es erst beim Zurueckspielen einer Sicherung von vor dem 06.09.2026: Dann werden die drei Spalten angelegt und sofort samt Inhalt weggeworfen, ohne Fehler, bei unveraenderter Zeilenzahl. Die Reparatur waere, die Liste nicht zu schreiben, sondern aus PRAGMA table_info abzuleiten -- so wie es checkListeErweitern fuer alle spaeteren Bereiche schon macht. Das ist ein Eingriff in einen Wanderungsweg auf echten Daten und wartet auf Filipes Wort. Co-Authored-By: Claude Opus 5 --- server/pruef-agentur.mjs | 46 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/server/pruef-agentur.mjs b/server/pruef-agentur.mjs index 0784f804..b0ce5ed9 100644 --- a/server/pruef-agentur.mjs +++ b/server/pruef-agentur.mjs @@ -26,7 +26,7 @@ schlimmere Ausgang. ===================================================================== */ -import { mkdtempSync, rmSync, appendFileSync } from "node:fs"; +import { mkdtempSync, rmSync, appendFileSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; @@ -61,6 +61,38 @@ const ok = (b, t) => { gemacht++; melde((b ? " ok " : " FEHL ") + t); if (!b nicht: Ein Modul wird nur einmal geladen. --------------------------------------------------------------------- */ let laufend = null; +/* DER DRITTE AUSGANG (11.09.2026). Diese Datei schreibt die + Serverausgabe immer schon mit -- und zeigte sie nur, wenn der Server + gar nicht erst hochkam. Faellt er spaeter mit 503 um (die Antwort bei + einem Datenbankfehler), standen hier 31-mal "FEHL" und kein einziges + Wort dazu, WARUM. Eine Pruefung, die nicht sagen kann, woran sie + scheitert, kostet eine Stunde Suchen. */ +let letzteAusgabe = () => ""; +/* UND SIE MUSS AUCH DANN KOMMEN, WENN DER LAUF ABSTUERZT. Playwright + wirft bei einem fehlenden Knopf eine Ausnahme -- der Prozess stirbt, + und mit ihm die Zusammenfassung samt Diagnose. Genau dann braucht + man sie am dringendsten. */ +function serverAusgabeZeigen(warum) { + const t = letzteAusgabe(); + console.log(""); + console.log(`=== Was der Server dazu gesagt hat (${warum}, letzte 1800 Zeichen) ===`); + console.log(t ? t.slice(-1800) : "(nichts -- der Server hat geschwiegen)"); + /* Und vollstaendig auf Zuruf, falls die Ursache weiter oben steht: + SERVERLOG=. Die letzten 1800 Zeichen zeigen den Schaden, + nicht immer seine Ursache. */ + if (t && process.env.SERVERLOG) { + writeFileSync(process.env.SERVERLOG, t); + console.log(`(vollstaendig in ${process.env.SERVERLOG})`); + } +} +for (const art of ["uncaughtException", "unhandledRejection"]) { + process.on(art, (e) => { + console.log(` +!! ${art}: ${e?.message || e}`); + serverAusgabeZeigen(art); + process.exit(1); + }); +} async function serverStarten() { const kind = spawn(process.execPath, [join(HIER, "index.js")], { env: { @@ -80,7 +112,11 @@ async function serverStarten() { if (kind.exitCode !== null) break; try { const a = await fetch(BASIS + "/workspace/", { redirect: "manual" }); - if (a.status < 500) { laufend = kind; return { kind, aus: () => aus }; } + if (a.status < 500) { + laufend = kind; + letzteAusgabe = () => aus; + return { kind, aus: () => aus }; + } } catch { /* noch nicht oben */ } } throw new Error("Server startete nicht:\n" + aus.slice(-1200)); @@ -709,5 +745,11 @@ await serverStoppen(); try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ } melde(`\n${gemacht} Pruefungen`); +if (fehler) { + const t = letzteAusgabe(); + melde(""); + melde("=== Was der Server dazu gesagt hat (letzte 1800 Zeichen) ==="); + melde(t ? t.slice(-1800) : "(nichts -- der Server hat geschwiegen)"); +} melde(fehler === 0 ? "ALLES IN ORDNUNG" : `${fehler} FEHLER`); process.exit(fehler ? 1 : 0);