func (s *Server) Shutdown() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	atomic.StoreInt32(&s.stop, 1)
	defer atomic.StoreInt32(&s.stop, 0)

	if s.ln == nil {
		return nil
	}

	if err := s.ln.Close(); err != nil {
		return err
	}

	if s.done != nil {
		close(s.done)
	}

	// 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.
	for {
		if open := atomic.LoadInt32(&s.open); open == 0 {
			break
		}
		// 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)
	}

	s.ln = nil
	return nil
}
func (s *Server) Shutdown() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	atomic.StoreInt32(&s.stop, 1)
	defer atomic.StoreInt32(&s.stop, 0)

	if s.ln == nil {
		return nil
	}

	if err := s.ln.Close(); err != nil {
		return err
	}

	if s.done != nil {
		close(s.done)
	}

	
	
	
	for {
		if open := atomic.LoadInt32(&s.open); open == 0 {
			break
		}
		
		
		
		time.Sleep(time.Millisecond * 100)
	}

	s.ln = nil
	return nil
}
func ( s * Server ) Shutdown ( ) error { s . mu . Lock ( ) defer s . mu . Unlock ( ) atomic . StoreInt32 ( & s . stop , 1 ) defer atomic . StoreInt32 ( & s . stop , 0 ) if s . ln == nil { return nil } if err := s . ln . Close ( ) ; err != nil { return err } if s . done != nil { close ( s . done ) } // 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. for { if open := atomic . LoadInt32 ( & s . open ) ; open == 0 { break } // 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 ) } s . ln = nil return nil }
// Shutdown gracefully shuts down the server without interrupting any active connections.
// Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle and then shut down.
//
// When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return nil.
// Make sure the program doesn't exit and waits instead for Shutdown to return.
//
// Shutdown does not close keepalive connections so its recommended to set ReadTimeout to something else than 0.
Shutdown gracefully shuts down the server without interrupting any active connections . Shutdown works by first closing all open listeners and then waiting indefinitely for all connections to return to idle and then shut down . When Shutdown is called Serve ListenAndServe and ListenAndServeTLS immediately return nil . Make sure the program doesn t exit and waits instead for Shutdown to return . Shutdown does not close keepalive connections so its recommended to set ReadTimeout to something else than 0 .