بررسی سلامت
نقاط پایانی بررسی سلامت به متعادلکنندههای بار، ارکستراتورهایی مانند Kubernetes و سیستمهای نظارت اجازه میدهند تأیید کنند برنامه شما در حال اجرا و آماده ارائه ترافیک است. یک تنظیم معمولی شامل دو نقطه پایانی است: liveness (آیا فرآیند زنده است؟) و readiness (آیا آماده پذیرش درخواستها است؟).
بررسی سلامت پایه
یک نقطه پایانی سلامت ساده که 200 OK برمیگرداند:
package main
import ( "net/http"
"github.com/gin-gonic/gin")
func main() { r := gin.Default()
r.GET("/healthz", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "ok"}) })
r.GET("/ping", func(c *gin.Context) { c.String(http.StatusOK, "pong") })
r.Run(":8080")}Liveness در مقابل readiness
در Kubernetes و محیطهای مشابه، معمولاً به دو نوع بررسی سلامت نیاز دارید:
- Liveness probe — بررسی میکند آیا فرآیند برنامه زنده است. اگر شکست بخورد، container راهاندازی مجدد میشود.
- Readiness probe — بررسی میکند آیا برنامه آماده مدیریت ترافیک است. اگر شکست بخورد، ترافیک به طور موقت متوقف میشود اما container راهاندازی مجدد نمیشود.
package main
import ( "database/sql" "net/http" "sync/atomic"
"github.com/gin-gonic/gin" _ "github.com/lib/pq")
var isReady atomic.Bool
func main() { db, err := sql.Open("postgres", "postgres://user:pass@localhost/dbname?sslmode=disable") if err != nil { panic(err) } defer db.Close()
r := gin.Default()
// Liveness: is the process alive? r.GET("/healthz", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "alive"}) })
// Readiness: can we serve traffic? r.GET("/readyz", func(c *gin.Context) { if !isReady.Load() { c.JSON(http.StatusServiceUnavailable, gin.H{"status": "not ready"}) return }
// Check database connectivity if err := db.Ping(); err != nil { c.JSON(http.StatusServiceUnavailable, gin.H{ "status": "not ready", "reason": "database unreachable", }) return }
c.JSON(http.StatusOK, gin.H{"status": "ready"}) })
// Mark as ready after initialization is complete isReady.Store(true)
r.Run(":8080")}پیکربندی Kubernetes
probeها را در مانیفست استقرار Kubernetes خود پیکربندی کنید:
apiVersion: apps/v1kind: Deploymentmetadata: name: my-gin-appspec: template: spec: containers: - name: app image: my-gin-app:latest ports: - containerPort: 8080 livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: path: /readyz port: 8080 initialDelaySeconds: 5 periodSeconds: 5بررسی وابستگیهای متعدد
برای برنامههایی با وابستگیهای متعدد، هر کدام را بررسی کنید و وضعیت جزئی گزارش دهید:
package main
import ( "context" "database/sql" "net/http" "time"
"github.com/gin-gonic/gin" "github.com/redis/go-redis/v9")
type HealthChecker struct { DB *sql.DB Redis *redis.Client}
func (h *HealthChecker) CheckHealth(c *gin.Context) { ctx, cancel := context.WithTimeout(c.Request.Context(), 2*time.Second) defer cancel()
checks := gin.H{} healthy := true
// Check database if err := h.DB.PingContext(ctx); err != nil { checks["database"] = gin.H{"status": "unhealthy", "error": err.Error()} healthy = false } else { checks["database"] = gin.H{"status": "healthy"} }
// Check Redis if err := h.Redis.Ping(ctx).Err(); err != nil { checks["redis"] = gin.H{"status": "unhealthy", "error": err.Error()} healthy = false } else { checks["redis"] = gin.H{"status": "healthy"} }
status := http.StatusOK if !healthy { status = http.StatusServiceUnavailable }
c.JSON(status, gin.H{ "status": map[bool]string{true: "healthy", false: "unhealthy"}[healthy], "checks": checks, })}تست
# Check livenesscurl -i http://localhost:8080/healthz
# Check readinesscurl -i http://localhost:8080/readyzخروجی مورد انتظار:
HTTP/1.1 200 OKContent-Type: application/json; charset=utf-8
{"status":"ready"}