Skip Timeout.timeout wrap when TCPSocket native connect_timeout is available#840
Open
Linuus wants to merge 2 commits into
Open
Skip Timeout.timeout wrap when TCPSocket native connect_timeout is available#840Linuus wants to merge 2 commits into
Linuus wants to merge 2 commits into
Conversation
…ailable
When a connect_timeout is provided on Ruby 3.4+ with TCPSocket, the
socket's native connect_timeout already enforces the timeout and raises
IO::TimeoutError on expiration. The outer Timeout.timeout wrap is
therefore redundant when native is in use, and creates a
Timeout::Request
that can leak under abnormal exit paths, pinning the calling Thread for
the process lifetime. In long-running workers (Sidekiq, etc.) this
results in slow memory growth from accumulated Threads.
This matches the existing method comment's intent ("Falls back to
Timeout.timeout on older Rubies or with custom socket classes") which
was previously not what the code actually did — the wrap was applied
unconditionally whenever a connect_timeout was set.
fc0ff9d to
110e972
Compare
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.
We are always wrapping in Timeout.timeout when a connect_timeout is set, even when native socket connect_timeout is available. The native timeout already enforces the limit and raises IO::TimeoutError, so the wrap is redundant.
Using Timeout.timeout is problematic: under certain exit paths, the Timeout::Request is not removed from the Timeout watcher's internal request queue, retaining the target Thread for the process lifetime. In long-running workers (Sidekiq, Puma in some configurations) this surfaces as slow memory growth.
Looks like this was meant to be avoided when native timeout support was added - the comment above the method even says "Falls back to Timeout.timeout on older Rubies or with custom socket classes" - but the code applies the wrap unconditionally. This PR makes the behavior match the comment.
I think this PR basically resolves #542