fix(requests): same processing state in list and detail, retries picked up on page view - #73
Conversation
…picked up on page view Symptom: the showcase list said "Der KI-Dienst ist nicht erreichbar" while the detail page only said "Die Dokumente werden gerade ausgewertet", and the request stayed there until the daily cron. Cause: the detail page rendered a fixed text for PROCESSING and ignored the failure the worker records (errorMessage, attempts, nextRetryAt); on Vercel Hobby only user actions or the daily cron drain the queue. Fix: processingNotice() gives the detail page the list's facts; opening the list or a request drains once after the response when JOB_DRAIN_INLINE=true, throttled to one run per 30 s and instance. Fixes #70 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Refs #70 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Frischer Review (/review-pr) – unabhängiger Reviewer-Agent ohne Umsetzungskontext, 2026-09-27Review PR #73 (nur eigener Diff, Basis #72) Geprüft und in Ordnung: Die Fokus-Tests laufen lokal grün (21/21). In der CI sind Urteil: changes requested – Es fehlen die Tests aus dem Testplan und die Pflege der Architekturkarte, dazu kommen der fremde CHANGELOG-Eintrag und die überlappenden Drains. Das ist vor Ready-for-review zu klären, nichts davon ist ein Sicherheitsblocker. |
README still said the SDK does not retry and lacked the two new settings; the CHANGELOG entry for #69 lived in the stacked #73 instead of the PR that changes the behaviour. The showcase runbook now sets the model budget below the web app's AI timeout so the worker never gives up while a model call is still running. The initial delay gets an upper bound so a misconfiguration cannot silently exceed the budget. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…to claude/fix-processing-state-70 # Conflicts: # CHANGELOG.md
… list row The fresh review of #73 found three gaps. The throttle counted starts, but a drain can run longer than its 30 s interval, so views could stack drains on one instance; a run gate now also waits for the previous run (and treats it as gone after the function limit). The detail notice derived its facts separately from the list and already drifted (NEW with an error, no scheduled retry); it now renders the list's row view, says "fällig" for a past retry time and promises no retry when none is scheduled. drainOnPageView itself is now unit-tested at the after() boundary. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The architecture map and its exceptions register listed upload, approval, reprocess and the cron route as the only drain triggers; #70 added page views, which is a new queue and cost trigger on the showcase and belongs in the map. The changelog names the new in-flight limit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Merge auf ausdrückliche Anweisung des Orchestrators (2026-09-27: „Merge und deploy“). |
Warum
Fixes #70 · gestapelt auf #72 (#69) und #68
Arbeitsstand
jobs.drain_runerzeugt.Was ist passiert (Klartext)
In der Demo stand in der Liste „Der KI-Dienst ist nicht erreichbar“, in der Detailansicht derselben Anfrage aber nur „Die Dokumente werden gerade ausgewertet“. Wer die Anfrage öffnete, sah also keinen Fehler. Außerdem blieb sie liegen, bis einmal am Tag der Nachlauf kam. Jetzt baut die Detailansicht ihren Hinweis aus genau denselben Angaben wie die Liste: letzter Fehler, bisherige Versuche und der nächste Versuch. Ist dessen Zeit schon vorbei, steht dort „fällig seit …“. Ist kein Versuch mehr geplant, verspricht die Seite auch keinen. Zusätzlich startet das Öffnen der Liste oder einer Anfrage im Showcase einen Nachlauf, höchstens alle 30 Sekunden und nie, solange der vorige noch läuft. Fällige Wiederholungen laufen dadurch einfach bei normaler Nutzung an. Lokal und in einer späteren Produktion mit eigenem Worker ändert sich nichts.
Plan-Pflicht (SYSTEM.md §4)
Impact Manifest
src/app/_server(Nachlauf-Auslöser) undsrc/app/requests(Liste, Detailseite, Hinweis);features/requestsverliert den zuvor hinzugefügten Export wieder. Keine Fachlogik der Queue geändert.JOB_DRAIN_INLINE=true; keine Drain-Flut.createRunGate(4),drainOnPageViewan derafter()-Grenze (4); Integration – die aufgerufene Drain-Runde ist dieselbe wie bei Upload/Freigabe/Cron und intests/integration/drain.test.tsgegen echtes Postgres/pg-boss geprüft. Abweichung vom Testplan in fix(requests): consistent processing state and pick-up of due retries on the showcase #70 siehe Nachweis.after()läuft nach dem Senden der Antwort (bestehender TestscheduleAfterResponse); die Seiten habenmaxDuration = 300; pg-boss hält Jobs exactly-once, auch bei parallelen Drains (bestehender Integrationstest „serverless drain and worker race“).JOB_DRAIN_INLINE=false(Runbook §9); Code per Revert-PR.Geändert
src/app/requests/processing-notice.ts(+ Test): Hinweis ausrequestRowView– Fehler bei NEW und PROCESSING, „fällig seit“ für vergangene Termine, kein Versprechen ohne geplanten Versuchsrc/app/requests/[id]/page.tsx: Hinweis aus der Zeilenansicht; Nachlauf beim Aufrufsrc/app/requests/page.tsx: Nachlauf beim Aufrufsrc/app/_server/drain-request.ts(+ Test):createRunGate(minIntervalMs, staleAfterMs)statt reiner Drosselsrc/app/_server/drain.ts(+ neuer Testdrain.test.ts):drainOnPageView()mit Sperre, gibt sie auch bei Fehlern freidocs/technical/architecture.md: Seitenaufruf als Drain-Auslöser (Ausnahmen-Register und Ablauf)CHANGELOG.md: Fixed-Eintrag fix(requests): consistent processing state and pick-up of due retries on the showcase #70 (der fix(ai-service): retry transient model errors within one extraction call #69-Eintrag liegt jetzt in fix(ai-service): retry transient model errors within one extraction call #72)Nachweis (SYSTEM.md §11)
verify:changed: grün –vitest src/app/_server src/app/requests33/33; zuerst rot:createRunGate is not a function, fehlendes Hinweis-Modul, zweiter Drain während laufendem erstemverify: lokal grün bis auf den bekannten Windows-Fall –lint0 Fehler (1 Warnung in einer git-ignorierten Plugin-Datei),typecheck,depcruise(keine Verletzungen),buildgrün; Unit 206/212 – die 6 Fehlschläge sind ausschließlichtests/architecture/dependency-rules.test.tsunter Windows (fix(tests): architecture test cannot start dependency-cruiser on Windows #78, Ursache belegt), in der Linux-CI grün; Integration 134/134 gegen Postgres + S3 (Docker)verify:full/ E2E-Spec: nicht betroffen – die Smoke-Specs prüfen keine Verarbeitungstexteafter()), und die ist an der I/O-Grenze unit-getestet. Der Hinweis ist eine reine Funktion der Zeilenansicht und damit vollständig unit-testbar; eine Seiten-Integration bräuchte einen Server-Component-Renderer, den das Projekt nicht hat.jobs.drain_runbei GET/requestsund bei der Detailseite (2026-09-27). Sichtprüfung des Hinweises im Wiederholungszustand folgt nach dem Deploy.requestflow-aiwar ein von mir abgebrochener Preview-Build ohne Bezug zu diesem DiffDoku-Entscheidung (genau eine)
docs/technical/architecture.md(Drain-Auslöser)[Unreleased](sichtbares Feature oder Verhalten – im selben PR, nie „später"): Fixed-Eintrag fix(requests): consistent processing state and pick-up of due retries on the showcase #70Entferntes oder Umbenanntes:
docs/+ README gegrept, Treffer bereinigt:processingNoticeausfeatures/requestsentfernt – keine Referenz indocs/oder README;createThrottledurchcreateRunGateersetzt – nur in Code und Tests referenziertDateigrößen und neue Bausteine (SYSTEM.md §7)
Dateien über 500 Zeilen im Diff (Ausnahmen: generierter Code, Lockfiles, Fixtures, Migrationen, Schemas, Ressourcen, Doku, Konfiguration):
Über 800 Zeilen mit neuer Fachlogik oder über 1000 Zeilen (P1/P2): nicht betroffen
Neue Shared-Komponente, Utility-Datei, Adapter oder fachlicher Service:
errorMessage,nextRetryAt,attemptsinsrc/appundsrc/features) und nach Drossel-/Sperr-Helfern (throttle,debounce,lock,inflight); gefunden:requestRowViewinsrc/app/requests/row-view.ts– der Hinweis nutzt sie jetzt statt eigener Ableitung; kein vorhandener Drossel- oder Sperr-Helfer außer pg-boss (Job-Ebene, nicht Seitenaufruf-Ebene)Subagent-Einsätze
Risiken / offene Punkte
🤖 Generated with Claude Code