munin/internal/web/handlers_bereitschaft.go

68 lines
2.2 KiB
Go

package web
import (
"context"
"log"
"net/http"
"sync/atomic"
"time"
)
// bereitZeitlimit begrenzt, wie lange /ready auf die Datenbank wartet. Ein
// Load-Balancer fragt typischerweise alle paar Sekunden mit eigenem
// Zeitlimit; eine Antwort nach 30 Sekunden hilft ihm nicht.
const bereitZeitlimit = 2 * time.Second
// handleLive antwortet, solange der Prozess läuft — ohne Datenbank, ohne
// Anmeldung. Siehe Routes in server.go, warum das getrennt von /ready ist.
func handleLive(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Write([]byte("ok\n"))
}
// handleReady prüft, ob die Kontroll-Datenbank antwortet: 200 "ok" oder 503
// "nicht bereit".
//
// Geprüft wird die Kontroll-Datenbank, weil ohne sie keine einzige Anfrage
// durchgeht (jede Key-Prüfung und jede Sitzung braucht sie). Unter
// PostgreSQL liegen die Workspaces auf demselben Server; ist er erreichbar,
// sind sie es auch.
//
// Der Grund steht nur im Log, nicht in der Antwort: /ready ist ohne
// Anmeldung erreichbar, und eine Fehlermeldung der Datenbank verrät Host,
// Port oder Benutzer.
func (s *Server) handleReady(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), bereitZeitlimit)
defer cancel()
err := s.control.Ping(ctx)
meldeBereitschaft(err)
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("Cache-Control", "no-store")
if err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte("nicht bereit\n"))
return
}
w.Write([]byte("ok\n"))
}
// bereitschaft merkt sich das letzte Ergebnis von /ready: 0 = noch nie
// geprüft, 1 = bereit, 2 = nicht bereit.
var bereitschaft atomic.Int32
// meldeBereitschaft schreibt nur einen WECHSEL ins Log. /ready wird alle paar
// Sekunden abgefragt; bei einem Ausfall stünde sonst dieselbe Zeile hundertfach
// da, und die Meldung, wann es wieder ging, ginge darin unter.
func meldeBereitschaft(err error) {
if err != nil {
if bereitschaft.Swap(2) != 2 {
log.Printf("Bereitschaft: Datenbank antwortet nicht — /ready meldet 503: %v", err)
}
return
}
if bereitschaft.Swap(1) == 2 {
log.Printf("Bereitschaft: Datenbank antwortet wieder — /ready meldet ok")
}
}