Retry on temporary net.Listener failure

Instead of stopping to listen, retry on temporary failure. This
can happen when running out of FDs.

Closes: https://todo.sr.ht/~emersion/soju/183
This commit is contained in:
Simon Ser 2022-01-19 22:35:46 +01:00
parent 950198a2b7
commit 69e9b6a439
2 changed files with 37 additions and 0 deletions

View File

@ -74,6 +74,8 @@ func (s *Identd) Delete(remoteAddr, localAddr string) {
}
func (s *Identd) Serve(ln net.Listener) error {
ln = &retryListener{Listener: ln}
for {
conn, err := ln.Accept()
if err != nil {

View File

@ -93,6 +93,36 @@ func (g *int64Gauge) Float64() float64 {
return float64(g.Value())
}
type retryListener struct {
net.Listener
Logger Logger
delay time.Duration
}
func (ln *retryListener) Accept() (net.Conn, error) {
for {
conn, err := ln.Listener.Accept()
if ne, ok := err.(net.Error); ok && ne.Temporary() {
if ln.delay == 0 {
ln.delay = 5 * time.Millisecond
} else {
ln.delay *= 2
}
if max := 1 * time.Second; ln.delay > max {
ln.delay = max
}
if ln.Logger != nil {
ln.Logger.Printf("accept error (retrying in %v): %v", ln.delay, err)
}
time.Sleep(ln.delay)
} else {
ln.delay = 0
return conn, err
}
}
}
type Config struct {
Hostname string
Title string
@ -328,6 +358,11 @@ func (s *Server) handle(ic ircConn) {
}
func (s *Server) Serve(ln net.Listener) error {
ln = &retryListener{
Listener: ln,
Logger: &prefixLogger{logger: s.Logger, prefix: fmt.Sprintf("listener %v: ", ln.Addr())},
}
s.lock.Lock()
s.listeners[ln] = struct{}{}
s.lock.Unlock()