http - 优雅地关闭多台服务器

标签 http go tcp

我有一个运行基本 HTTP 服务器并接受 TCP 连接的应用程序。

基本伪代码如下:

package main

import (
    "log"
    "net"
    "net/http"
)

func main() {
    // create serve HTTP server.
    serveSvr := http.NewServeMux()
    serveSvr.HandleFunc("/", handler())

    // create server error channel
    svrErr := make(chan error)

    // start HTTP server.
    go func() {
        svrErr <- http.ListenAndServe(":8080", serveSvr)
    }()

    // start TCP server
    go func() {
        lnr, err := net.Listen("tcp", ":1111")
        if err != nil {
            svrErr <- err
            return
        }
        defer lnr.Close()

        for {
            conn, err := lnr.Accept()
            if err != nil {
                log.Printf("connection error: %v", err)
                continue
            }
            // code to handle each connection
        }
    }()

    select {
    case err := <-svrErr:
        log.Print(err)
    }
}

我在单独的 goroutine 中运行两个服务器,我需要一种方法来在其中一个失败时优雅地关闭它们。例如;如果 HTTP 服务器出错,我该如何返回并关闭 TCP 服务器/执行任何清理工作?

最佳答案

首先保留对 http 服务器和 tcp 监听器的引用,以便您稍后可以关闭它们。

创建单独的错误 channel ,以便您知道哪个路径返回了错误,并对它们进行缓冲,以便发送始终可以完成。

要确保在退出之前完成您想要尝试的任何清理,您可以将 WaitGroup 添加到服务器 goroutines。

我对你的例子的简单扩展可能是这样的:

var wg sync.WaitGroup

// create  HTTP server.
serveSvr := http.NewServeMux()
serveSvr.HandleFunc("/", handler())
server := &http.Server{Addr: ":8080", Handler: serveSvr}

// create http server error channel
httpErr := make(chan error, 1)

// start HTTP server.
wg.Add(1)
go func() {
    defer wg.Done()
    httpErr <- server.ListenAndServe()
    // http cleanup
}()

tcpErr := make(chan error, 1)
listener, err := net.Listen("tcp", ":1111")
if err != nil {
    tcpErr <- err
} else {
    // start TCP server
    wg.Add(1)
    go func() {
        defer wg.Done()
        defer listener.Close()
        for {
            conn, err := listener.Accept()
            if err != nil {
                if ne, ok := err.(net.Error); ok && ne.Temporary() {
                    // temp error, wait and continue
                    continue
                }
                tcpErr <- err

                // cleanup TCP
                return
            }

            // code to handle each connection
        }
    }()
}
select {
case err := <-httpErr:
    // handle http error and close tcp listen
    if listener != nil {
        listener.Close()
    }
case err := <-tcpErr:
    // handle tcp error and close http server
    server.Close()
}

// you may also want to receive the error from the server
// you shutdown to log

// wait for any final cleanup to finish
wg.Wait()

关于http - 优雅地关闭多台服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43473411/

相关文章:

tcp - 使用 ninenine ranch 实现 Long live tcp 连接

java - OkHttpClient 将 http URL 重定向到 Https 并给出带有 https URL 的 SSLException

go - 在golang中 `something`是什么意思

go - 如何模拟调用 io.Copy 的函数

xml - 戈朗 : XML attributes from another struct

network-programming - Intranet 与 Internet 应用程序中的校验和验证

javascript - 检查URL在纯JavaScript中是否有效

asp.net - Angular HttpClient 调用缺少查询字符串和授权 header

android - 如何从 Android 中的 URL 获取数据?

python - 使用 python 在 Elastic-beanstalk 中部署 TCP 服务器