doufanglian7585 2015-10-29 12:04
浏览 40
已采纳

正常关闭负面的WaitGroup

I have tried to implement a graceful shutdown of the go server, as described in this blog post http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/. The main bits are the following.

Custom listener:

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
}

Custom Conn:

type gracefulConn struct {
    net.Conn
}

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

The idea is when the program receives SIGTERM, it stops serving new connections and just waits for the httpWg.Wait() for existing connections to finish. This approach works locally, but when I deploy it, sometimes I receive a panic in the gracefulConn.Close() at httpWg.Done() line:

panic: sync: negative WaitGroup counter

The panic happens not when I stop the server but just during routine serving. How is it possible, that there are more Close() calls then Accept() calls? Or am I missing something?

P.S. I have tried to add stopped property and a mutex to gracefullConn, so in Close it locks the mutex and checks stopped to ensure we stop it only once. However, I still received the same panic.

  • 写回答

2条回答 默认 最新

  • dongnianchou7047 2015-10-29 12:50
    关注

    Close() can be called multiple times so you definitely need to check for that in func (w gracefulConn) Close() error.

    P.S. I have tried to add stopped property and a mutex to gracefullConn, so in Close it locks the mutex and checks stopped to ensure we stop it only once. However, I still received the same panic.

    Keep in mind that gracefulConn if passed as a value not a reference so any mutexes/flags will not work as expected. So be sure to turn c = gracefulConn{Conn: c} into c = &gracefulConn{Conn: c}.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示
  • ¥15 求三国群英传pl国战时间的修改方法
  • ¥15 matlab代码代写,需写出详细代码,代价私
  • ¥15 ROS系统搭建请教(跨境电商用途)
  • ¥15 AIC3204的示例代码有吗,想用AIC3204测量血氧,找不到相关的代码。
  • ¥20 CST怎么把天线放在座椅环境中并仿真