2023-07-03 06:49:05 +00:00
|
|
|
package health
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
2023-07-23 06:48:04 +00:00
|
|
|
"go.ntppool.org/common/logger"
|
2023-07-03 06:49:05 +00:00
|
|
|
"golang.org/x/exp/slog"
|
2023-07-09 04:18:38 +00:00
|
|
|
"golang.org/x/sync/errgroup"
|
2023-07-03 06:49:05 +00:00
|
|
|
)
|
|
|
|
|
2023-07-23 06:48:04 +00:00
|
|
|
type Server struct {
|
|
|
|
log *slog.Logger
|
|
|
|
healthFn http.HandlerFunc
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewServer(healthFn http.HandlerFunc) *Server {
|
|
|
|
if healthFn == nil {
|
|
|
|
healthFn = basicHealth
|
|
|
|
}
|
|
|
|
srv := &Server{
|
|
|
|
log: logger.Setup(),
|
|
|
|
healthFn: healthFn,
|
|
|
|
}
|
|
|
|
return srv
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *Server) SetLogger(log *slog.Logger) {
|
|
|
|
srv.log = log
|
|
|
|
}
|
|
|
|
|
|
|
|
func (srv *Server) Listen(ctx context.Context, port int) error {
|
|
|
|
srv.log.Info("Starting health listener", "port", port)
|
2023-07-03 06:49:05 +00:00
|
|
|
|
|
|
|
serveMux := http.NewServeMux()
|
|
|
|
|
2023-07-23 06:48:04 +00:00
|
|
|
serveMux.HandleFunc("/__health", srv.healthFn)
|
2023-07-03 06:49:05 +00:00
|
|
|
|
2023-07-23 06:48:04 +00:00
|
|
|
hsrv := &http.Server{
|
2023-07-03 06:49:05 +00:00
|
|
|
Addr: ":" + strconv.Itoa(port),
|
|
|
|
ReadTimeout: 10 * time.Second,
|
|
|
|
WriteTimeout: 20 * time.Second,
|
|
|
|
IdleTimeout: 120 * time.Second,
|
|
|
|
Handler: serveMux,
|
|
|
|
}
|
|
|
|
|
2023-07-09 04:18:38 +00:00
|
|
|
g, ctx := errgroup.WithContext(ctx)
|
|
|
|
|
|
|
|
g.Go(func() error {
|
2023-07-23 06:48:04 +00:00
|
|
|
err := hsrv.ListenAndServe()
|
2023-07-03 06:49:05 +00:00
|
|
|
if err != http.ErrServerClosed {
|
2023-07-23 06:48:04 +00:00
|
|
|
srv.log.Warn("health check server done listening", "err", err)
|
2023-07-09 04:18:38 +00:00
|
|
|
return err
|
2023-07-03 06:49:05 +00:00
|
|
|
}
|
2023-07-09 04:18:38 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-07-03 06:49:05 +00:00
|
|
|
|
|
|
|
<-ctx.Done()
|
|
|
|
|
2023-07-09 04:18:38 +00:00
|
|
|
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
g.Go(func() error {
|
2023-07-23 06:48:04 +00:00
|
|
|
if err := hsrv.Shutdown(ctx); err != nil {
|
|
|
|
srv.log.Error("health check server shutdown failed", "err", err)
|
2023-07-09 04:18:38 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2023-07-03 06:49:05 +00:00
|
|
|
|
2023-07-09 04:18:38 +00:00
|
|
|
return g.Wait()
|
2023-07-03 06:49:05 +00:00
|
|
|
}
|
|
|
|
|
2023-07-23 06:48:04 +00:00
|
|
|
// HealthCheckListener runs simple http server on the specified port for
|
|
|
|
// health check probes
|
|
|
|
func HealthCheckListener(ctx context.Context, port int, log *slog.Logger) error {
|
|
|
|
srv := NewServer(nil)
|
|
|
|
srv.SetLogger(log)
|
|
|
|
return srv.Listen(ctx, port)
|
|
|
|
}
|
|
|
|
|
2023-07-03 06:49:05 +00:00
|
|
|
func basicHealth(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.WriteHeader(200)
|
|
|
|
w.Write([]byte("ok"))
|
|
|
|
}
|