diff options
| author | Shulhan <ms@kilabit.info> | 2026-02-11 21:43:11 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2026-02-11 21:43:11 +0700 |
| commit | 5b41090e6c523a1e66047329e51c2b0db280a581 (patch) | |
| tree | 10635c88bc6510a7405259199fa6f99675936240 /lib/http/server.go | |
| parent | 37c0e3f259204842c1ac82a04effb6c12e76078d (diff) | |
| download | pakakeh.go-5b41090e6c523a1e66047329e51c2b0db280a581.tar.xz | |
lib/http: implement server auto shutdown when idle
In the `ServerOptions`, we add option `ShutdownIdleDuration` when set to
non-zero value it will start a timer.
When the timer expired, the server will stop accepting new connection and
then shutting down.
This allow de-activating HTTP server when no connections received after
specific duration to reduce the system resources.
Diffstat (limited to 'lib/http/server.go')
| -rw-r--r-- | lib/http/server.go | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/lib/http/server.go b/lib/http/server.go index 4501cb9f..bbd1cf3e 100644 --- a/lib/http/server.go +++ b/lib/http/server.go @@ -46,6 +46,8 @@ type Server struct { // Modifying the value of Options after server has been started may // cause undefined effects. Options ServerOptions + + shutdownIdleTimer *time.Timer } // NewServer create and initialize new HTTP server that serve root directory @@ -323,6 +325,14 @@ func (srv *Server) registerPut(ep *Endpoint) (err error) { // ServeHTTP handle mapping of client request to registered endpoints. func (srv *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) { + if srv.shutdownIdleTimer != nil { + ok := srv.shutdownIdleTimer.Reset(srv.Options.ShutdownIdleDuration) + if !ok { + // Timer had expired or been stopped. + return + } + } + req.URL.Path = strings.TrimPrefix(req.URL.Path, srv.Options.BasePath) switch req.Method { @@ -358,6 +368,31 @@ func (srv *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) { // Start the HTTP server. func (srv *Server) Start() (err error) { + if srv.Options.ShutdownIdleDuration == 0 { + return srv.serve() + } + + srv.shutdownIdleTimer = time.NewTimer(srv.Options.ShutdownIdleDuration) + go func() { + err = srv.serve() + }() + ever := true + for ever { + select { + case <-srv.shutdownIdleTimer.C: + ever = false + ok := srv.shutdownIdleTimer.Stop() + if !ok { + // Stop has been called manually. + break + } + err = srv.Stop(0) + } + } + return err +} + +func (srv *Server) serve() (err error) { if srv.Server.TLSConfig == nil { if srv.Options.Listener == nil { err = srv.Server.ListenAndServe() @@ -380,6 +415,13 @@ func (srv *Server) Start() (err error) { // Stop the server using Shutdown method. The wait is set default and minimum // to five seconds. func (srv *Server) Stop(wait time.Duration) (err error) { + if srv.shutdownIdleTimer != nil { + ok := srv.shutdownIdleTimer.Stop() + if !ok { + // The timer has been stopped by other goroutine. + return nil + } + } var defWait = 5 * time.Second if wait <= defWait { wait = defWait |
