mirror of https://github.com/status-im/consul.git
agent/grpc: use a separate channel for closing the Accept
Closing l.conns can lead to a race and a 'panic: send on closed chan' when a connection is in the middle of being handled when the server is shutting down. Found using '-race -count=800'
This commit is contained in:
parent
d8299670cc
commit
19da9c3a9b
|
@ -22,7 +22,7 @@ func NewHandler(addr net.Addr, register func(server *grpc.Server)) *Handler {
|
|||
)
|
||||
register(srv)
|
||||
|
||||
lis := &chanListener{addr: addr, conns: make(chan net.Conn)}
|
||||
lis := &chanListener{addr: addr, conns: make(chan net.Conn), done: make(chan struct{})}
|
||||
return &Handler{srv: srv, listener: lis}
|
||||
}
|
||||
|
||||
|
@ -51,14 +51,16 @@ func (h *Handler) Shutdown() error {
|
|||
type chanListener struct {
|
||||
conns chan net.Conn
|
||||
addr net.Addr
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// Accept blocks until a connection is received from Handle, and then returns the
|
||||
// connection. Accept implements part of the net.Listener interface for grpc.Server.
|
||||
func (l *chanListener) Accept() (net.Conn, error) {
|
||||
select {
|
||||
case c, ok := <-l.conns:
|
||||
if !ok {
|
||||
case c := <-l.conns:
|
||||
return c, nil
|
||||
case <-l.done:
|
||||
return nil, &net.OpError{
|
||||
Op: "accept",
|
||||
Net: l.addr.Network(),
|
||||
|
@ -66,8 +68,6 @@ func (l *chanListener) Accept() (net.Conn, error) {
|
|||
Err: fmt.Errorf("listener closed"),
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (l *chanListener) Addr() net.Addr {
|
||||
|
@ -75,7 +75,7 @@ func (l *chanListener) Addr() net.Addr {
|
|||
}
|
||||
|
||||
func (l *chanListener) Close() error {
|
||||
close(l.conns)
|
||||
close(l.done)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue