mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-13 22:42:08 +00:00
fix(multiplayer): report allocator readiness
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package allocator
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Health records only complete successful cycles. Readiness ages out when
|
||||
// provider or durable-store work repeatedly fails or stalls, while liveness
|
||||
// remains independent so Kubernetes does not restart a healthy process for a
|
||||
// dependency outage.
|
||||
type Health struct {
|
||||
mu sync.RWMutex
|
||||
lastSuccessfulCycle time.Time
|
||||
}
|
||||
|
||||
func (h *Health) ObserveSuccessfulCycle(at time.Time) {
|
||||
if h == nil || at.IsZero() {
|
||||
return
|
||||
}
|
||||
h.mu.Lock()
|
||||
h.lastSuccessfulCycle = at
|
||||
h.mu.Unlock()
|
||||
}
|
||||
|
||||
func (h *Health) Ready(now time.Time, maxStale time.Duration) bool {
|
||||
if h == nil || now.IsZero() || maxStale <= 0 {
|
||||
return false
|
||||
}
|
||||
h.mu.RLock()
|
||||
lastSuccess := h.lastSuccessfulCycle
|
||||
h.mu.RUnlock()
|
||||
return !lastSuccess.IsZero() && !now.Before(lastSuccess) && now.Sub(lastSuccess) <= maxStale
|
||||
}
|
||||
|
||||
// RoleHandler exposes metrics plus distinct process-liveness and dependency-
|
||||
// progress readiness endpoints on the allocator's private listener.
|
||||
func RoleHandler(metrics *Metrics, health *Health, maxStale time.Duration, now func() time.Time) http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/metrics", MetricsHandler(metrics))
|
||||
mux.HandleFunc("/healthz", methodGet(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
_, _ = w.Write([]byte("ok\n"))
|
||||
}))
|
||||
mux.HandleFunc("/readyz", methodGet(func(w http.ResponseWriter, _ *http.Request) {
|
||||
if now == nil || !health.Ready(now(), maxStale) {
|
||||
http.Error(w, "allocator has no recent successful cycle", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
_, _ = w.Write([]byte("ready\n"))
|
||||
}))
|
||||
return mux
|
||||
}
|
||||
|
||||
func methodGet(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user