68 lines
2.2 KiB
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")
|
|
}
|
|
}
|