Buggy
← บทความทั้งหมด

Health Check Endpoint: ทำไมทุก Service ควรมี /healthz

· 2 min read

#monitoring#devops

Service ที่ไม่มี health check endpoint คือ service ที่ระบบ orchestrator (Kubernetes, load balancer, uptime monitor) มองไม่เห็นว่ากำลัง "ตายอยู่แบบเงียบๆ" หรือเปล่า บทความนี้สรุปสิ่งที่ health check ที่ดีควรทำ และข้อผิดพลาดที่พบบ่อยที่สุด

Liveness vs Readiness ต่างกันยังไง

สองคำนี้มักถูกใช้ปนกัน ทั้งที่ตอบคำถามคนละข้อ

LivenessReadiness
ตอบคำถามprocess ยัง "มีชีวิต" อยู่ไหมprocess พร้อมรับ traffic ไหม
ถ้า failorchestrator restart containerorchestrator หยุดส่ง traffic มาชั่วคราว แต่ไม่ restart
เช็คอะไรevent loop ยังตอบสนอง, ไม่ deadlockdependency สำคัญ (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