package app import ( "context" "errors" "net" "net/http" "time" ) // ServeHTTP runs an HTTP server and treats graceful shutdown as a normal lifecycle exit. func ServeHTTP(server *http.Server, listener net.Listener) error { if server == nil { return errors.New("http server is required") } if listener == nil { return errors.New("http listener is required") } err := server.Serve(listener) if errors.Is(err, http.ErrServerClosed) { return nil } return err } // ShutdownHTTP first drains accepted requests and then force-closes the server if the drain budget is exceeded. func ShutdownHTTP(server *http.Server, timeout time.Duration) error { if server == nil { return nil } ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() if err := server.Shutdown(ctx); err != nil { return errors.Join(err, server.Close()) } return nil }