From 29c50cf485b5d664f45a4fa12891a9a8a30cb316 Mon Sep 17 00:00:00 2001 From: 014-code <2402143478@qq.com> Date: Fri, 3 Jul 2026 12:57:22 +0800 Subject: [PATCH] fix(connection): reload onRequest in onProcess to avoid dead loop" -m "When SetOnRequest is called from inside the onConnect callback (or from inside a previous onRequest call) the task goroutine spawned by onProcess kept using the stale handler snapshot captured as a closure parameter. If the old handler (typically a no-op placeholder) failed to consume the input buffer, the for-loop at the START label would never break, the processing lock would never be released, and the goroutine would spin forever, effectively killing the connection. This change reloads the latest handler from c.onRequestCallback at the entry of START and at the end of each onRequest call inside the processing loop, so any handler swap made by the user is picked up immediately. Closes #421 --- connection_onevent.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/connection_onevent.go b/connection_onevent.go index 20ead2ab..f1a6130c 100644 --- a/connection_onevent.go +++ b/connection_onevent.go @@ -209,6 +209,12 @@ func (c *connection) onProcess(onConnect OnConnect, onRequest OnRequest) (proces c.unlock(connecting) } START: + // Reload the latest onRequest handler from the atomic to avoid using a + // stale snapshot when SetOnRequest is called from inside onConnect or + // the previous onRequest call. Otherwise the old (typically no-op) + // handler would be invoked repeatedly and the goroutine would fall + // into a dead loop because it never consumes the buffered input. + onRequest, _ = c.onRequestCallback.Load().(OnRequest) // The `onRequest` must be executed at least once if conn have any readable data, // which is in order to cover the `send & close by peer` case. if onRequest != nil && c.Reader().Len() > 0 { @@ -225,6 +231,8 @@ func (c *connection) onProcess(onConnect OnConnect, onRequest OnRequest) (proces break } _ = onRequest(c.ctx, c) + // Reload to pick up handler changes (SetOnRequest) made by the call above. + onRequest, _ = c.onRequestCallback.Load().(OnRequest) } // handling callback if connection has been closed. if closedBy != none {