Repository navigation
fix(health): report a cold-starting AI service as starting, not failed - #88
Conversation
…ting On the showcase the AI service is a scaled-to-zero container; its cold start (~6 s) exceeded the probe's time limit, so /api/health read "aiService: failed" although the service was fine a few seconds later. An informational dependency without an answer in time is now "starting" (the probe itself wakes the container); an answered error or a refused connection stays "failed". Required checks (database, storage) keep failing on a timeout with 503. Fixes #81 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Übergabe (2026-09-28, Sitzungsende)
|
… the real boundary The fresh review of #88 showed that in production the probe's own 2 s abort always fires first, so a wrong address, dropped packets or a hanging service would read `starting` for ever. withStartupGrace now turns timeouts that last longer than 30 s into `failed` (a cold start takes about 6 s); an answer or a real error ends the period. An integration test lets a real server accept and never answer, so the undici abort path is covered, not only a hand-made DOMException. Docs now state the 2 s probe limit and that a failed probe is not cached. Refs #81 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Frischer Review (/review-pr) – unabhängiger Reviewer-Agent ohne Umsetzungskontext, 2026-09-28Geprüft: Diff, #81, Route,
Urteil: changes requested – Test an der echten Netzgrenze fehlt, Plan-Pflicht falsch beantwortet; die Änderung der öffentlichen API braucht danach eine menschliche Freigabe. Bearbeitung (208eeca): 1 → |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Merge auf Freigabe des Orchestrators (2026-09-28: „merge getestetes“) – CI grün, Grenzfall-Integrationstest 6/6. |
Warum
Fixes #81
Arbeitsstand
/api/healthnicht mehr wie ein Ausfall.startingfür informative Abhängigkeiten ohne Antwort in der Frist; nach 30 s ohne Antwort wiederfailed(Review); Unit-Tests und Integrationsfall an der echten Netzgrenze; Doku (API, Betrieb, Runbook §8); CHANGELOG.Was ist passiert (Klartext)
Die Statusseite
/api/healthmeldete den KI-Dienst nach einer Pause als „failed“, obwohl er wenige Sekunden später lief: Der Dienst schläft nach 5 Minuten ohne Aufrufe ein, und das Aufwachen dauert etwa 6 Sekunden – länger, als die Statusseite wartet. Jetzt unterscheidet sie: Antwortet der Dienst gar nicht rechtzeitig, heißt es „starting“ (er wacht gerade auf – der Aufruf selbst weckt ihn); antwortet er mit einem Fehler oder ist nicht erreichbar, bleibt es „failed“. Für Datenbank und Speicher ändert sich nichts.Plan-Pflicht (SYSTEM.md §4)
Impact Manifest
observability(health.ts:DependencyResult,withStartupGrace),app(Route/api/health); Doku./api/health– additiv:dependencies.aiServicekann jetzt auchstartingsein (Befund aus dem Review: öffentliche API ⇒ Auslöser). Status und HTTP-Code fürchecksunverändert. Im Repo wertet niemandaiServicemit festen Werten aus (CIcurl -f, Playwright nur die URL).startingbei hängender Abhängigkeit und beiTimeoutError; Pflicht-Check hängt →failed+ 503; Karenz: länger als 30 s →failed, eine Antwort beendet sie, ein neuer Kaltstart bekommt eine neue; echter Fehler sofortfailed. Integration – echter Server nimmt an und antwortet nie →starting.pingAiServicebricht nach 2 s mitTimeoutErrorab (vor der 3-s-Frist der Route);cachedForcacht keine abgelehnten Promises; gemessener Kaltstart ≈ 5,6 s (ADR-0001 D11 amendment)./api/health-Antwort beim Kaltstart bis zu ~6 s auf und lässt trotzdem offen, ob der Dienst startet oder hängt;startingplus 30-s-Karenz antwortet sofort und meldet einen echten Ausfall nach 30 s.ok/failedkennen, sehen einen neuen Wert – im Repo gibt es keine; Rollback per Revert.Geändert
src/features/observability/health.ts:DependencyResult = CheckResult | "starting";withStartupGrace(check, graceMs)(länger als 30 s ohne Antwort ⇒failed), von der Route/api/healthmit 30 s genutzt;settle()unterscheidet Zeitüberschreitung (eigene Frist oderAbortSignal.timeout=TimeoutError) von Fehler; Pflicht-Checks werten eine Zeitüberschreitung weiter alsfailedsrc/features/observability/index.ts: TypenCheckResult,DependencyResultexportiertsrc/features/observability/health.test.ts: 5 neue Fälle (hängende Abhängigkeit →starting;TimeoutError→starting; hängender Pflicht-Check →failed+ 503; Karenz über 30 s →failedund Neustart; echter Fehler sofortfailed)tests/integration/health.test.ts: echter Server, der annimmt und nie antwortet →startingdocs/technical/api.md,docs/technical/operations.md,docs/technical/deployment-vercel.md§8: ZustandstartingCHANGELOG.md: Fixed-Eintrag fix(health): AI dependency reads as failed during a container cold start #81 im neuen[Unreleased](nach dem Release v0.1.0)Nachweis (SYSTEM.md §11)
verify:changed: grün –vitest health.test.ts12/12; zuerst rot: die 3 ersten neuen Fälle (failedstattstarting), nach dem Review die 2 Karenz-Fälle (withStartupGrace is not a function)verify: grün – CI am PR (2 min 10 s): Unit 237/237, Integration 19 Dateien grün, daruntertests/integration/health.test.ts6/6 mit dem neuen Grenzfall; lokaltypecheck,lintgrün (Docker lokal aus)verify:full/ E2E-Spec: nicht betroffenDoku-Entscheidung (genau eine)
docs/technical/api.md,docs/technical/operations.md,docs/technical/deployment-vercel.md§8[Unreleased](sichtbares Feature oder Verhalten – im selben PR, nie „später"): Fixed-Eintrag fix(health): AI dependency reads as failed during a container cold start #81Entferntes oder Umbenanntes:
docs/+ README gegrept, Treffer bereinigt: nichts entferntDateigröß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:
Subagent-Einsätze
Keine.
Risiken / offene Punkte
starting): menschliche Freigabe laut api-Regel – allgemein erteilt am 2026-09-28 („merge getestetes“).🤖 Generated with Claude Code