fix: websocket timeouts after around 50-60 seconds#239
Conversation
WalkthroughThe PR adds a buffered semaphore field to wsConnection and a wsMaxConcurrentHandlers constant, initializes the semaphore in NewWebSocketHandler, and changes handleWSMethodCall to attempt a non-blocking acquire of the semaphore and run handlers in a goroutine (releasing the semaphore when done). If acquisition fails, a JSON-RPC server-error is returned immediately. sendJSON now calls SetWriteDeadline(wsWriteWait) before WriteJSON and returns any deadline-setting error. 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@server/websocket.go`:
- Around line 210-222: The code spawns an unbounded goroutine per WebSocket
request; add a bounded concurrency semaphore to limit concurrent handlers (e.g.,
add a semaphore field like handlerSem on the wsConn or a package-level limiter)
and acquire a token before starting the goroutine (if acquisition fails respond
with ErrCodeServerError/ResourceExhausted via wsConn.sendError), then run the
handler inside the goroutine and defer release of the token after handler
finishes; update the block that calls handler(req.Params) to acquire the token,
spawn the goroutine only when acquired, and ensure wsConn.sendResponse and
wsConn.sendError still execute inside the goroutine and after the token is
released.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a2c3cceb-6eb9-4d52-8d10-9a45abf9b669
📒 Files selected for processing (1)
server/websocket.go
adds a buffered-channel semaphore on wsConnection to bound goroutine growth; requests beyond the limit are rejected immediately with a server error response
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
server/websocket.go (1)
223-233:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winRecover panics inside the handler goroutine (
handleWSMethodCall)
handler(req.Params)runs in a spawned goroutine, but the defer only releaseshandlerSem; there’s norecover(), so any panic in the handler can crash the whole server.🛡️ Minimal hardening patch
go func() { - defer func() { <-wsConn.handlerSem }() + defer func() { + <-wsConn.handlerSem + if r := recover(); r != nil { + log.Printf("panic executing method %s: %v", req.Method, r) + _ = wsConn.sendError(req.ID, ErrCodeServerError, "Server error", "internal handler panic") + } + }() result, err := handler(req.Params) if err != nil { log.Printf("Error executing method %s: %v", req.Method, err) wsConn.sendError(req.ID, ErrCodeServerError, "Server error", err.Error()) return🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/websocket.go` around lines 223 - 233, The spawned goroutine calling handler(req.Params) must recover from panics to avoid crashing the server: wrap the body with a defer that calls recover(), logs the panic (including req.Method and stack trace), sends a server error back via wsConn.sendError(req.ID, ErrCodeServerError, "Server error", <panic info>), and still releases the handlerSem; modify the anonymous goroutine in handleWSMethodCall so the existing defer that reads from handlerSem is preserved and a new defer handles recover(), logging and sending the error when a panic occurs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@server/websocket.go`:
- Around line 223-233: The spawned goroutine calling handler(req.Params) must
recover from panics to avoid crashing the server: wrap the body with a defer
that calls recover(), logs the panic (including req.Method and stack trace),
sends a server error back via wsConn.sendError(req.ID, ErrCodeServerError,
"Server error", <panic info>), and still releases the handlerSem; modify the
anonymous goroutine in handleWSMethodCall so the existing defer that reads from
handlerSem is preserved and a new defer handles recover(), logging and sending
the error when a panic occurs.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 69bca0fe-dfc4-4531-8c77-449fe50c4b2b
📒 Files selected for processing (1)
server/websocket.go
No description provided.