/* DIE NOTBREMSE FÜR PRÜFUNGEN --------------------------------------------------------------------- DER FEHLER, DEN DAS VERHINDERT (06.09.2026, drei Stunden gekostet) index.js setzt am Ende bewusst zwei Auffangnetze: process.on("uncaughtException", (f) => console.error(…)); process.on("unhandledRejection", (g) => console.error(…)); Für den echten Betrieb ist das genau richtig: Ein Fehler in einer Nebensache darf die Website nicht offline nehmen. Für eine PRÜFUNG ist es das Gegenteil. Eine Prüfung importiert index.js in denselben Prozess -- und erbt damit die Netze. Wenn dann ihr eigener Ablauf abstürzt (ein Playwright-Klick auf ein Element, das es nicht gibt), wird der Absturz nur PROTOKOLLIERT. Danach passiert nichts mehr: Das Skript ist zu Ende, aber der Express-Server hält den Prozess am Leben. Kein Fehler, kein Ergebnis, kein Ende. Genau so blieb pruef-call-kategorien.mjs drei Stunden stehen -- und mit ihr der gesamte Regressionslauf, der auf sie wartete. Von aussen sieht "läuft noch" genauso aus wie "hängt für immer". --------------------------------------------------------------------- WAS DIESE DATEI TUT Sie hängt ZWEI eigene Zuhörer daneben (process.on ergänzt, es ersetzt nicht -- die Meldung von index.js bleibt also erhalten) und beendet den Lauf mit einem Fehler. Und sie stellt einen Wecker: Wer nach der Frist noch läuft, wartet nicht mehr, er hängt. Beides greift NUR in Prüfungen. Der Betrieb importiert diese Datei nicht und behält seine Netze unverändert. --------------------------------------------------------------------- BENUTZUNG — nach dem Import von index.js, vor dem ersten Browser: import { notbremse } from "./helfer-notbremse.mjs"; await import("./index.js"); notbremse(300_000, "die Kategorienpruefung"); */ /** @param {number} fristMs Nach dieser Zeit gilt der Lauf als haengend. * @param {string} wer Name für die Meldung. */ import { standWache } from "./helfer-standwache.mjs"; export function notbremse(fristMs = 300_000, wer = "diese Pruefung") { /* ==== UND HAT SICH DER STAND WAEHREND DES LAUFS GEAENDERT? ======= (01.10.2026, angestossen von der zweiten Claude-Sitzung.) Am 06./07.09.2026 wurden fuenf Gesamtlaeufe gestartet und dreimal davon WAEHREND des Laufs weitergebaut. Jeder dieser Laeufe hat einen Stand gemessen, den es schon nicht mehr gab -- rund zwei Stunden Wartezeit ohne einen einzigen Befund. Am 01.10. dieselbe Lage, nur anders: Zwei Sitzungen im Verzeichnis, eine misst, die andere speichert. Aufgefallen ist es nur, weil die andere es von sich aus gesagt hat. HIER UND NICHT IN 179 DATEIEN: Wer eine Notbremse hat, bekommt die Standwache mit. Das ist dieselbe Ueberlegung wie bei der Notbremse selbst -- einzelne Dateien nachzuruesten hilft nur bis zur naechsten ohne. SIE HAELT NICHTS AN. Ein Lauf, dessen Grundlage sich verschoben hat, ist nicht „nicht in Ordnung" -- er ist NICHT NACHSEHBAR. Deshalb Rueckgabewert 3 und ein ausdruecklicher Satz, dass das kein Befund am Code ist. */ standWache(wer); let schonAus = false; const raus = (art, was) => { if (schonAus) return; schonAus = true; console.error(`\n FEHL ${wer}: ${art}`); console.error(` ${String(was?.stack || was).split("\n").slice(0, 6).join("\n ")}`); console.error(`\n Abgebrochen. Ohne diese Notbremse wuerde der Prozess`); console.error(` weiterlaufen, weil der Server ihn am Leben haelt --`); console.error(` ohne Fehler, ohne Ergebnis, ohne Ende.\n`); process.exit(1); }; process.on("uncaughtException", (f) => raus("unbehandelter Fehler", f)); process.on("unhandledRejection", (g) => raus("unbehandeltes Versprechen", g)); /* unref(): Der Wecker allein soll den Prozess NICHT am Leben halten. Sonst haette ausgerechnet die Notbremse dafuer gesorgt, dass eine fertige Pruefung noch fuenf Minuten herumsteht. */ const wecker = setTimeout(() => { console.error(`\n FEHL ${wer} HING: nach ${Math.round(fristMs / 1000)} s war sie ` + `noch nicht fertig.`); console.error(` Haeufigste Ursachen: ein Warten auf ein Element, das nie kommt,`); console.error(` oder eine Verbindung, die nie endet (Ereignisstrom).\n`); process.exit(1); }, fristMs); wecker.unref?.(); return () => clearTimeout(wecker); }