Health Check Endpoint: ทำไมทุก Service ควรมี /healthz
· 2 min read
Service ที่ไม่มี health check endpoint คือ service ที่ระบบ orchestrator (Kubernetes, load balancer, uptime monitor) มองไม่เห็นว่ากำลัง "ตายอยู่แบบเงียบๆ" หรือเปล่า บทความนี้สรุปสิ่งที่ health check ที่ดีควรทำ และข้อผิดพลาดที่พบบ่อยที่สุด
Liveness vs Readiness ต่างกันยังไง
สองคำนี้มักถูกใช้ปนกัน ทั้งที่ตอบคำถามคนละข้อ
| Liveness | Readiness | |
|---|---|---|
| ตอบคำถาม | process ยัง "มีชีวิต" อยู่ไหม | process พร้อมรับ traffic ไหม |
| ถ้า fail | orchestrator restart container | orchestrator หยุดส่ง traffic มาชั่วคราว แต่ไม่ restart |
| เช็คอะไร | event loop ยังตอบสนอง, ไม่ deadlock | dependency สำคัญ (DB, cache, upstream) เชื่อมต่อได้ |
การเอาสองอย่างนี้ไปรวมเป็น endpoint เดียวกันคือสาเหตุอันดับต้นๆ ที่ทำให้เกิด restart loop: ถ้า /healthz เช็ค database connection ด้วย แล้ว database ล่มชั่วคราว orchestrator จะ restart container รัวๆ ทั้งที่ตัว process เองไม่ได้มีปัญหาอะไรเลย
ตัวอย่าง implementation ใน Next.js
แยก endpoint เป็นสองเส้นทางชัดเจน
// app/api/healthz/route.ts — liveness: ตอบเร็ว ไม่แตะ dependency ภายนอก
export function GET() {
return Response.json({ status: "ok" });
}// app/api/readyz/route.ts — readiness: เช็ค dependency ที่จำเป็นต่อการรับ traffic จริง
export async function GET() {
try {
await db.query("SELECT 1");
return Response.json({ status: "ready" });
} catch {
return Response.json({ status: "not-ready" }, { status: 503 });
}
}ข้อสำคัญ: /healthz ต้อง ไม่ await อะไรที่ช้าหรือ fail ได้จากภายนอก เพราะจุดประสงค์ของมันคือบอกแค่ว่า process ยังรันอยู่เท่านั้น
สิ่งที่ไม่ควรทำใน health check
- เช็ค dependency ที่ไม่จำเป็นต่อการรับ request — เช่นเช็ค connection ไป analytics service ที่ retry ทีหลังได้ ไม่ควรทำให้ readiness fail
- ทำงานหนัก — ห้าม query ที่ scan ทั้งตาราง หรือคำนวณอะไรที่ใช้เวลานาน เพราะ endpoint นี้จะถูกเรียกทุกๆ ไม่กี่วินาที
- ไม่ใส่ timeout — ถ้า dependency แขวนเฉยๆ (ไม่ error ไม่ timeout) health check จะแขวนตามไปด้วย แล้ว orchestrator ก็จะตัดสินใจช้าตามไปด้วย
- return 200 เสมอไม่ว่าจะเกิดอะไรขึ้น — บาง team ทำแบบนี้เพื่อ "กัน alert รบกวน" ซึ่งเท่ากับปิดตาตัวเองจากปัญหาจริง
เอาไปต่อกับอะไรได้บ้าง
ถ้า deploy บน Kubernetes ให้ผูก /healthz กับ livenessProbe และ /readyz กับ readinessProbe ตามคู่มือ Configure Liveness, Readiness and Startup Probes ส่วนถ้าใช้ uptime monitor ภายนอก (เช่นเช็คทุก 1 นาทีจากนอก network) ให้ชี้ไปที่ /healthz เท่านั้น ไม่ใช่ /readyz — เพราะ readiness ที่ fail ชั่วคราวระหว่าง deploy ไม่ควรถูกนับเป็น incident