From ffa5d4ac1389bccfd4cf2fca8d60d2b99c259a5d Mon Sep 17 00:00:00 2001 From: Rock Brock Date: Sun, 31 May 2026 07:23:23 +0500 Subject: [PATCH] fix(jitsi): break out of rtcpKeepalive loop on persistent write errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the JVB bridge disconnects but the session is not yet closed (e.g. during a pending reconnect), rtcpKeepalive spins indefinitely logging "rtcp keepalive write: io: read/write on closed pipe" every 5 seconds. The process appears alive but is functionally dead — systemd Restart=always never triggers and the instance becomes permanently wedged. Add an error counter that triggers requestReconnect after 3 consecutive WriteRTCP failures, allowing the supervisor to tear down and re-establish the bridge connection. Reset the counter on any successful write. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/engine/jitsi/jitsi.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/internal/engine/jitsi/jitsi.go b/internal/engine/jitsi/jitsi.go index 0981b92..f14b94f 100644 --- a/internal/engine/jitsi/jitsi.go +++ b/internal/engine/jitsi/jitsi.go @@ -572,9 +572,11 @@ type negotiator interface { func (s *Session) rtcpKeepalive(pc *webrtc.PeerConnection) { defer s.wg.Done() const interval = 5 * time.Second + const maxErrors = 3 ticker := time.NewTicker(interval) defer ticker.Stop() pkts := []rtcp.Packet{&rtcp.ReceiverReport{}} + errCount := 0 for { select { case <-s.done: @@ -584,7 +586,15 @@ func (s *Session) rtcpKeepalive(pc *webrtc.PeerConnection) { if s.closed.Load() { return } - logger.Debugf("jitsi: rtcp keepalive write: %v", err) + errCount++ + logger.Debugf("jitsi: rtcp keepalive write (%d/%d): %v", errCount, maxErrors, err) + if errCount >= maxErrors { + logger.Warnf("jitsi: rtcp keepalive giving up after %d errors", maxErrors) + s.requestReconnect("rtcp keepalive dead") + return + } + } else { + errCount = 0 } } }