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") } }