73f77f1624
This makes systemd not put unit into fail mode when stopping INFO: * make sure to use signals.RegisterCloser for everything that should be closed on interrupt * for any net.Listeners created make sure to wrap them with network.WrapListener and register with signals.RegisterCloser
58 lignes
1 Kio
Go
58 lignes
1 Kio
Go
package network
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
)
|
|
|
|
var ErrListenerStopped = errors.New("listener was stopped")
|
|
|
|
// GracefulListener provides safe and graceful net.Listener wrapper that prevents error on graceful shutdown
|
|
type GracefulListener struct {
|
|
listener net.Listener
|
|
stop chan int
|
|
}
|
|
|
|
func (l *GracefulListener) Accept() (net.Conn, error) {
|
|
for {
|
|
c, err := l.listener.Accept()
|
|
select {
|
|
case <-l.stop:
|
|
if c != nil {
|
|
c.Close()
|
|
}
|
|
close(l.stop)
|
|
l.stop = nil
|
|
return nil, ErrListenerStopped
|
|
default:
|
|
|
|
}
|
|
if err != nil {
|
|
neterr, ok := err.(net.Error)
|
|
if ok && neterr.Timeout() && neterr.Temporary() {
|
|
continue
|
|
}
|
|
}
|
|
return c, err
|
|
}
|
|
}
|
|
|
|
func (l *GracefulListener) Close() (err error) {
|
|
l.listener.Close()
|
|
if l.stop != nil {
|
|
l.stop <- 0
|
|
}
|
|
return
|
|
}
|
|
|
|
func (l *GracefulListener) Addr() net.Addr {
|
|
return l.listener.Addr()
|
|
}
|
|
|
|
// WrapListener wraps a net.Listener such that it can be closed gracefully
|
|
func WrapListener(l net.Listener) net.Listener {
|
|
return &GracefulListener{
|
|
listener: l,
|
|
stop: make(chan int),
|
|
}
|
|
}
|