aboutsummaryrefslogtreecommitdiff
path: root/server.go
diff options
context:
space:
mode:
authorGravatar kinggo <lilong.21@bytedance.com> 2022-11-20 19:26:36 +0800
committerGravatar GitHub <noreply@github.com> 2022-11-20 13:26:36 +0200
commit49951353c83ac7b3ca9a78570dbea0c970b6d801 (patch)
tree8f3be03c091834f7c7f11eb8b84ba6c2fd7e1c7a /server.go
parentstyle: modify typo and remove repeated type conversions (#1437) (diff)
downloadfasthttp-49951353c83ac7b3ca9a78570dbea0c970b6d801.tar.gz
fasthttp-49951353c83ac7b3ca9a78570dbea0c970b6d801.tar.bz2
fasthttp-49951353c83ac7b3ca9a78570dbea0c970b6d801.zip
feat: add ShutdownWithContext (#1383)v1.42.0
Diffstat (limited to 'server.go')
-rw-r--r--server.go28
1 files changed, 24 insertions, 4 deletions
diff --git a/server.go b/server.go
index c603e7a..0be703c 100644
--- a/server.go
+++ b/server.go
@@ -1829,6 +1829,17 @@ func (s *Server) Serve(ln net.Listener) error {
//
// Shutdown does not close keepalive connections so its recommended to set ReadTimeout and IdleTimeout to something else than 0.
func (s *Server) Shutdown() error {
+ return s.ShutdownWithContext(context.Background())
+}
+
+// ShutdownWithContext gracefully shuts down the server without interrupting any active connections.
+// ShutdownWithContext works by first closing all open listeners and then waiting for all connections to return to idle or context timeout and then shut down.
+//
+// When ShutdownWithContext is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil.
+// Make sure the program doesn't exit and waits instead for Shutdown to return.
+//
+// ShutdownWithContext does not close keepalive connections so its recommended to set ReadTimeout and IdleTimeout to something else than 0.
+func (s *Server) ShutdownWithContext(ctx context.Context) (err error) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -1840,7 +1851,7 @@ func (s *Server) Shutdown() error {
}
for _, ln := range s.ln {
- if err := ln.Close(); err != nil {
+ if err = ln.Close(); err != nil {
return err
}
}
@@ -1851,7 +1862,10 @@ func (s *Server) Shutdown() error {
// Closing the listener will make Serve() call Stop on the worker pool.
// Setting .stop to 1 will make serveConn() break out of its loop.
- // Now we just have to wait until all workers are done.
+ // Now we just have to wait until all workers are done or timeout.
+ ticker := time.NewTicker(time.Millisecond * 100)
+ defer ticker.Stop()
+END:
for {
s.closeIdleConns()
@@ -1861,12 +1875,18 @@ func (s *Server) Shutdown() error {
// This is not an optimal solution but using a sync.WaitGroup
// here causes data races as it's hard to prevent Add() to be called
// while Wait() is waiting.
- time.Sleep(time.Millisecond * 100)
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ break END
+ case <-ticker.C:
+ continue
+ }
}
s.done = nil
s.ln = nil
- return nil
+ return err
}
func acceptConn(s *Server, ln net.Listener, lastPerIPErrorTime *time.Time) (net.Conn, error) {