lib/http: fix race between Serve() and Shutdown()

This was discovered by the race detector.
This commit is contained in:
Nick Craig-Wood 2025-04-05 13:35:04 +01:00
parent 90ea4a73ad
commit 084e35c49d

View File

@ -229,7 +229,8 @@ type Server struct {
cfg Config cfg Config
template *TemplateConfig template *TemplateConfig
htmlTemplate *template.Template htmlTemplate *template.Template
usingAuth bool // set if we are using auth middleware usingAuth bool // set if we are using auth middleware
mu sync.Mutex // mutex protects RW variables below
atexitHandle atexit.FnHandle atexitHandle atexit.FnHandle
} }
@ -524,7 +525,9 @@ func (s *Server) Serve() {
go ii.serve(&s.wg) go ii.serve(&s.wg)
} }
// Install an atexit handler to shutdown gracefully // Install an atexit handler to shutdown gracefully
s.mu.Lock()
s.atexitHandle = atexit.Register(func() { _ = s.Shutdown() }) s.atexitHandle = atexit.Register(func() { _ = s.Shutdown() })
s.mu.Unlock()
} }
// Wait blocks while the server is serving requests // Wait blocks while the server is serving requests
@ -543,10 +546,12 @@ const gracefulShutdownTime = 10 * time.Second
// Shutdown gracefully shuts down the server // Shutdown gracefully shuts down the server
func (s *Server) Shutdown() error { func (s *Server) Shutdown() error {
// Stop the atexit handler // Stop the atexit handler
s.mu.Lock()
if s.atexitHandle != nil { if s.atexitHandle != nil {
atexit.Unregister(s.atexitHandle) atexit.Unregister(s.atexitHandle)
s.atexitHandle = nil s.atexitHandle = nil
} }
s.mu.Unlock()
for _, ii := range s.instances { for _, ii := range s.instances {
expiry := time.Now().Add(gracefulShutdownTime) expiry := time.Now().Add(gracefulShutdownTime)
ctx, cancel := context.WithDeadline(context.Background(), expiry) ctx, cancel := context.WithDeadline(context.Background(), expiry)