From 69e9b6a439751a42b7b67ba548de00653b8a38bc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 19 Jan 2022 22:35:46 +0100 Subject: [PATCH] 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 --- ident.go | 2 ++ server.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/ident.go b/ident.go index 7498839..a596a86 100644 --- a/ident.go +++ b/ident.go @@ -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 { diff --git a/server.go b/server.go index be4be53..0622b27 100644 --- a/server.go +++ b/server.go @@ -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()