feat(pool): add connect_timeout option for spawned connection tasks - #4369
Open
mmustafasenoglu wants to merge 2 commits into
Open
feat(pool): add connect_timeout option for spawned connection tasks#4369mmustafasenoglu wants to merge 2 commits into
mmustafasenoglu wants to merge 2 commits into
Conversation
When connect_timeout is set, Pool::acquire() spawns the connection attempt as a separate task instead of running it inline. This ensures that if acquire() is cancelled or times out, the connection attempt continues in the background. If it succeeds, the connection is returned to the pool's idle queue. This addresses the issue where acquire() cancellation would abort in-flight connection attempts, causing connection churn under high contention (see transact-rs#3315, transact-rs#3132, transact-rs#2848). Closes transact-rs#3513
- Import path: futures_intrusive::channel::shared::oneshot_channel (not ::channel::oneshot_channel) - ChannelSendError<T> wrapping: destructure with Err(ChannelSendError(result)) - rx.receive().await returns Option<T>, use ok_or(Error::PoolTimedOut) Fixes CI failures in sqlx transact-rs#4369.
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.
Description
This PR adds a new
connect_timeoutoption toPoolOptionsthat, when set, spawns the connection attempt as a separate task inPool::acquire(). This ensures that ifacquire()is cancelled or times out, the connection attempt continues in the background rather than being aborted.If the connection succeeds but no one picks it up (because
acquire()was cancelled), the connection is automatically returned to the pool's idle queue.Problem
Currently,
acquire()wraps both the semaphore/idle-connection check and the actual connection creation in a single timeout. Ifacquire()is cancelled (e.g., due to its own timeout), the in-flightconnect()call is also aborted. Under high contention, this can cause:DecrementSizeGuarddrops, pool size fluctuatesThis is the root cause behind several reported issues: #3315, #3132, #2848.
Solution
When
connect_timeoutis set onPoolOptions:crate::rt::spawnconnect_timeoutfutures_intrusive::channel::oneshotchannel communicates the result backacquire()is cancelled (receiver dropped), the sender detects this and returns the connection to the pool's idle queueWhen
connect_timeoutis not set (the default), the existing behavior is preserved exactly -- no breaking changes.Changes
sqlx-core/src/pool/options.rs: Addedconnect_timeout: Option<Duration>field, builder method, getter, and updatedDebug/Cloneimplssqlx-core/src/pool/inner.rs: Modifiedacquire()to spawn connection as a separate task whenconnect_timeoutis setUsage
Notes
futures_intrusive::channel::oneshot_channelfor cross-runtime compatibility (works with tokio, async-std, smol)connect_timeoutis not setCloses #3513