srv.Shutdown(ctx) 是 Go 标准库 net/http 包中的 http.Server 类型的方法。它用于优雅地关闭 HTTP 服务器,确保所有正在处理的请求完成后再退出。

以下是 srv.Shutdown(ctx) 的核心代码示例,展示了如何在服务器关闭过程中等待所有请求完成。请注意,实际源码会有所不同,以下代码仅为核心逻辑的简化版本:

// http/server.go

// Shutdown initiates a graceful shutdown of the server, waiting for
// currently active connections to finish.
func (srv *Server) Shutdown(ctx context.Context) error {
    // Signal the server to stop accepting new connections.
    srv.setClosing()

    // Close the listener so no new connections will be accepted.
    if err := srv.Listener.Close(); err != nil && err != ErrServerClosed {
        return err
    }

    // Create a channel to signal when all active connections have finished.
    done := make(chan struct{})

    // Start a goroutine to wait for active connections to close.
    go func() {
        srv.wg.Wait()
        close(done)
    }()

    // Wait for either the connections to close or the context to timeout.
    select {
    case <-ctx.Done():
        return ctx.Err() // Return context error if context is canceled or timed out.
    case <-done:
        return nil // Successfully closed after all connections are done.
    }
}

// setClosing sets the server to a "closing" state to stop accepting new connections.
func (srv *Server) setClosing() {
    srv.mu.Lock()
    defer srv.mu.Unlock()
    srv.closing = true
}

关键部分解析

  1. 停止接受新连接

    • srv.setClosing() 设置服务器为关闭状态,标志着服务器将不再接受新的连接。
  2. 关闭监听器

    • srv.Listener.Close() 关闭监听器,防止新的连接到达。注意,如果监听器已经关闭或者出现错误,Shutdown 方法会处理这些情况。
  3. 等待活跃连接关闭

    • srv.wg.Wait() 等待所有活跃的连接处理完毕。srv.wg 是一个 sync.WaitGroup,用于跟踪活动连接的数量。
  4. 处理超时或完成信号

    • select 语句用于等待 ctx.Done()(上下文的超时或取消)或 done 通道(所有连接完成)。如果上下文超时或被取消,返回上下文错误;如果所有连接完成,则返回 nil

相关代码

  • srv.wgsync.WaitGroup 类型,用于跟踪活动连接。
  • srv.setClosing() 标记服务器状态为“关闭”,停止接受新连接。
  • srv.Listener 是实际的网络监听器,负责接受新的连接。

Shutdown 方法的实际源码可能包含更多细节和处理逻辑,但核心思想是在关闭过程中确保所有活跃连接得到处理,并在超时或取消时优雅退出。