llmrouter: Slot an das Verbindungssignal binden (cancel feuert nicht)

Gegenprobe am Produktivrouter nach dem ersten Fix: Ein abgebrochener Stream
gab den Slot WEITERHIN nicht frei -- cancel() im TransformStream wird von Bun
beim Verbindungsabbruch nicht aufgerufen. Immerhin griff die zweite Haerte:
statt zwei Stunden Stille gab es nach 30 s ein 503 mit Grund.

Jetzt haengt der Slot an req.signal, das beim Abbruch zuverlaessig feuert, plus
einem Sicherheitsnetz von 660 s (laenger als der Upstream-Timeout darf kein
Slot gehalten werden). Die Freigabe ist gegen Doppelaufruf gesichert, ein
spaeteres flush() schadet also nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-07 20:23:36 +02:00
co-authored by Claude Opus 5
parent ff62e751ed
commit 948ab84afe
+10
View File
@@ -348,6 +348,16 @@ Bun.serve({
let freigeben: () => void;
try {
freigeben = await belegen(ziel.upstreamName, ziel.upstream);
// Der Slot haengt am LEBEN DER VERBINDUNG, nicht am Ende des Streams.
// Gegenprobe am 2026-09-07: cancel() im TransformStream feuert in Bun
// NICHT, wenn der Client abbricht -- der Slot blieb belegt, und erst die
// 30-s-Frist machte daraus ein 503 statt Stille (42i/intern#1283).
// req.signal feuert dagegen zuverlaessig; die Freigabe ist gegen
// Doppelaufruf gesichert, ein spaeteres flush() schadet also nicht.
// Dazu ein Sicherheitsnetz: laenger als der Upstream-Timeout darf kein
// Slot gehalten werden, egal was passiert.
req.signal.addEventListener("abort", () => freigeben(), { once: true });
setTimeout(() => freigeben(), 660_000);
} catch (e) {
if (e instanceof SlotFrist) {
eintrag.status = 503; eintrag.fehler = e.message; abschliessen();