Files
0pt/app/api/ready/route.ts
Claude 0062edbec3
CI (SIAX Cloud) / integration (push) Skipped
masterplan-lock / check (push) Successful in 6s
CI (SIAX Cloud) / security (push) Successful in 15s
masterplan-lock / check (pull_request) Successful in 4s
Security Scan (SIAX Cloud) / security (push) Successful in 27s
CI (SIAX Cloud) / security (pull_request) Successful in 23s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 24s
CI (SIAX Cloud) / quality (push) Successful in 45s
CI (SIAX Cloud) / integration (pull_request) Successful in 31s
CI (SIAX Cloud) / quality (pull_request) Successful in 40s
fix(readiness): /api/ready svarade 200 med en död motor i produktion
Mätt live 2026-09-25 mot produktionsdeployen (0pt.app / api.0pt.app,
container shxd6lepxuxfsjsp0ath3z1g-172514162615 på server6, uppe 17,9 h,
Docker-status "healthy" hela tiden):

    GET /api/health -> HTTP/1.1 200 OK
      {"ok":false,"service":"0pt-web","db":"ok","queue":"not_configured",
       "engine":"error","stripe":"not_configured",
       "detail":{"engine":"This operation was aborted"}}

    GET /api/ready  -> HTTP/1.1 200 OK
      {"ready":true,"service":"0pt-web","db":"ok","engine":"error",...}

ENGINE_URL pekade på http://0pt-engine:8000. Mätt inifrån containern:
`getent hosts 0pt-engine` ger ingen post, och det finns ingen sådan
container på någon av server5-11. Ett direktanrop mot motorn misslyckas
efter ~5 s (DNS). Datamotorn — 0pt:s hela produkt — var alltså BORTA, och
samtliga signaler ovanför den var gröna: Docker healthy, /api/health 200,
/api/ready 200.

`ok:false` i en 200-kropp är ingen signal. Ingenting i kedjan läser
kroppar; allt läser statuskoder och exitkoder.

isReady skilde tidigare bara på "db ok". Den skillnad som saknades är inte
konfigurerad-vs-ej-konfigurerad utan FRÅNVARANDE-vs-TRASIG:

  * not_configured / not_integrated -> fortsatt ready. 0pt är byggt för att
    kunna köra utan motor, Stripe och kö (se .env.example).
  * error -> INTE ready. Statusen "error" betyder att någon medvetet
    konfigurerade beroendet och att en riktig round trip mot det just
    misslyckades. Det är inte längre en valfri integration.

Ändrar ingenting i driften i dag: container-HEALTHCHECK pekar på
/api/health (liveness) och Dockerfilen säger uttryckligen att en
readiness-probe inte ska peka dit. Den här ändringen gör bara att den
ärliga ytan faktiskt blir ärlig, så en yttre övervakning kan använda den.

Regressionstest tillagt; verifierat att det FALLER mot den gamla isReady
(1 failed | 18 passed) och passerar mot den nya (24 passed över
health-checks/ready/health).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 13:34:42 +02:00

35 lines
1.3 KiB
TypeScript

import { NextResponse } from "next/server";
import { checkAllDependencies, isReady } from "@/lib/health-checks";
// GET /api/ready — readiness (BACKLOG P0-3, CD-04/OBS-04: "no /ready route
// existed at all").
//
// Unlike GET /api/health (liveness -- always 200 while the process can
// respond), this fails closed: 503 whenever a load-bearing dependency isn't
// both configured AND actually reachable. Point a load balancer / Coolify
// readiness probe at this route, not /api/health, to stop routing traffic to
// an instance whose database is down without restarting it.
//
// Load-bearing by absence: only the database (see
// `lib/health-checks.ts#isReady`) -- engine/stripe/queue are optional
// integrations 0pt is designed to run without. Load-bearing by FAILURE: all
// of them. A dependency somebody configured and that then fails a live round
// trip makes this instance not-ready, whichever one it is.
export async function GET() {
const deps = await checkAllDependencies();
const ready = isReady(deps);
return NextResponse.json(
{
ready,
service: "0pt-web",
db: deps.db.status,
queue: deps.queue.status,
engine: deps.engine.status,
stripe: deps.stripe.status,
ts: new Date().toISOString(),
},
{ status: ready ? 200 : 503 },
);
}