package server import ( "context" "net" "net/http" "sync" "time" ) // Server wraps an HTTP server with graceful shutdown support. type Server struct { httpServer *http.Server shutdownTimeout time.Duration listener net.Listener listenerMu sync.RWMutex healthChecker *HealthChecker } // New creates a new Server with the given configuration. func New(listenAddr string, shutdownTimeout time.Duration, handler http.Handler) *Server { return &Server{ httpServer: &http.Server{ Addr: listenAddr, Handler: handler, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, }, shutdownTimeout: shutdownTimeout, healthChecker: NewHealthChecker(false, false), } } // ListenAndServe starts the HTTP server and blocks until it exits. // It returns the error from the server (if any), which will be // http.ErrServerClosed if Shutdown was called. func (s *Server) ListenAndServe() error { listener, err := net.Listen("tcp", s.httpServer.Addr) if err != nil { return err } s.listenerMu.Lock() s.listener = listener s.listenerMu.Unlock() return s.httpServer.Serve(listener) } // Shutdown gracefully shuts down the server. It stops accepting new // connections and waits for in-flight requests to complete, with a // bounded deadline. If the deadline is exceeded, it returns an error. func (s *Server) Shutdown(ctx context.Context) error { // Create a new context with the shutdown timeout shutdownCtx, cancel := context.WithTimeout(ctx, s.shutdownTimeout) defer cancel() return s.httpServer.Shutdown(shutdownCtx) } // Addr returns the network address the server is listening on. func (s *Server) Addr() string { s.listenerMu.RLock() defer s.listenerMu.RUnlock() if s.listener != nil { return s.listener.Addr().String() } return s.httpServer.Addr } // HealthChecker returns the server's health checker. func (s *Server) HealthChecker() *HealthChecker { return s.healthChecker } // SetHealthChecker sets the server's health checker. func (s *Server) SetHealthChecker(hc *HealthChecker) { s.healthChecker = hc } // SetHandler sets the server's HTTP handler. func (s *Server) SetHandler(handler http.Handler) { s.httpServer.Handler = handler }