Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FIX 1:
unregisterConnectionnever calledconn.Close()(primary leak).The map entry was deleted but the underlying TCP socket was never closed. Each time a user navigated to a new page the old conn was removed from the map but its fd stayed open. This is the main culprit for the 3-4 hour exhaustion window.
FIX 2: TOCTOU race on connection limit check.
The count check and registration were not atomic. Under rapid reconnects (exactly your use case) multiple goroutines could pass the limit simultaneously, allowing more connections than intended and wasting fds.
FIX 3:
defer unregisterConnectionis now the single fd-release point.Since
unregisterConnectionnow callsconn.Close(), the deferred call in wsHandler is the single authoritative cleanup path regardless of how the handler exits.FIX 4: Ping goroutine leaked on every disconnect (secondary leak).
for range ticker.Chas no exit condition.ticker.Stop()prevents new ticks but the goroutine blocks on the channel forever, keeping a reference to conn alive. Replaced with a select on a done channel that is closed when the handler returns.FIX 5:
startTokenRevalidationticker never stopped.Refactored to accept a
stopCh <-chan struct{}anddefer ticker.Stop()so the goroutine exits cleanly on shutdown.FIX 6: Log file fd never closed.
setupLoggingopened the file but had no way to close it. The handle is now stored inlogFileHandleand deferred-closed inrun().FIX 7:
db.Close()never called.The database connection pool holds fds.
defer db.Close()added inrun().FIX 8: Offline cleanup goroutine ticker never stopped.
Same pattern as FIX 5 converted to
selectonstopCh.FIX 9: Reduce code complexity for
func run()