【问题标题】:Go graceful shutdown negative WaitGroupGo 优雅关闭负 WaitGroup
【发布时间】:2016-01-29 13:35:18
【问题描述】:

我已尝试实现 go 服务器的正常关闭,如这篇博文 http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/ 中所述。主要内容如下。

自定义监听器:

var httpWg sync.WaitGroup  // initialised in the other part

type gracefulListener struct {
    net.Listener
    stop    chan error
    stopped bool
}

func newGracefulListener(l net.Listener) (gl *gracefulListener) {
    gl = &gracefulListener{Listener: l, stop: make(chan error)}
    go func() {
        _ = <-gl.stop
        gl.stopped = true
        gl.stop <- gl.Listener.Close()
    }()
    return
}

func (gl *gracefulListener) Accept() (c net.Conn, err error) {
    c, err = gl.Listener.Accept()
    if err != nil {
        return
    }

    c = gracefulConn{Conn: c}  // wrap using our custom connection

    httpWg.Add(1)  // increase the counter
    return
}

func (gl *gracefulListener) Close() error {
    if gl.stopped {
        return syscall.EINVAL
    }
    gl.stop <- nil
    return <-gl.stop
}

func (gl *gracefulListener) File() *os.File {
    tl := gl.Listener.(*net.TCPListener)
    fl, _ := tl.File()
    return fl
}

自定义连接:

type gracefulConn struct {
    net.Conn
}

func (w gracefulConn) Close() error {
    httpWg.Done()  // <- panics sometimes
    return w.Conn.Close()
}

这个想法是当程序收到 SIGTERM 时,它会停止提供新的连接,并等待 httpWg.Wait() 完成现有连接。 这种方法在本地有效,但是当我部署它时,有时我会在gracefulConn.Close()httpWg.Done() 行收到恐慌:

panic: sync: negative WaitGroup counter

恐慌不是在我停止服务器时发生,而是在例行服务期间发生。 怎么可能有更多的Close() 电话然后Accept() 电话?还是我错过了什么?

附:我尝试将stopped 属性和互斥锁添加到gracefullConn,因此在Close 中它会锁定互斥锁并检查stopped 以确保我们只停止它一次。但是,我仍然感到同样的恐慌。

【问题讨论】:

  • 很可能Close() 在同一个gracefulConn 实例上被调用了两次。如果不查看其余代码,很难说出这是如何发生的。

标签: go


【解决方案1】:

Close() 可以被多次调用,所以你肯定需要在func (w gracefulConn) Close() error 中进行检查。

附:我试图向 GracefullConn 添加停止的属性和互斥锁,因此在关闭时它会锁定互斥锁并检查停止以确保我们只停止一次。但是,我仍然感到同样的恐慌。

请记住,gracefulConn 如果作为值而不是引用传递,那么任何互斥体/标志都不会按预期工作。所以一定要把c = gracefulConn{Conn: c}变成c = &amp;gracefulConn{Conn: c}。

【讨论】:

    【解决方案2】:

    我认为这是错误的方法。

    您并不真正关心连接是否打开 - 持久连接呢?

    您关心的是您是否在积极使用这些连接。我认为最好将 WaitGroup 放入自定义 ServeMux 到 ServeHTTP 方法中。然后,您可以在函数调用周围使用WaitGroup。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-26
      • 2014-02-05
      • 2019-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多