Skip to content

Add configurable idle connection timeout (ADO #39970)#4295

Open
priyankatiwari08 wants to merge 16 commits into
dotnet:mainfrom
priyankatiwari08:feature/idle-connection-timeout-pr1
Open

Add configurable idle connection timeout (ADO #39970)#4295
priyankatiwari08 wants to merge 16 commits into
dotnet:mainfrom
priyankatiwari08:feature/idle-connection-timeout-pr1

Conversation

@priyankatiwari08
Copy link
Copy Markdown
Contributor

@priyankatiwari08 priyankatiwari08 commented May 19, 2026

Adds a configurable idle connection timeout for pooled SqlConnection instances.

Compatibility and behavior:

  • The existing default remains unchanged: IdleTimeout defaults to 300 seconds.
  • Idle-expiration behavior is gated by Switch.Microsoft.Data.SqlClient.UseLegacyIdleTimeoutBehavior, which defaults to true so current behavior is preserved unless the switch is disabled.
  • When the legacy switch is disabled, the configured IdleTimeout controls when pooled connections are considered idle and eligible for expiration.

Additional changes:

  • Updates both pool implementations to honor the new behavior consistently.
  • Adds tests for parsing, legacy compatibility, and idle-expiration behavior.

Implements spec User Stories 1, 2, 4 + FR-009 of US3 from specs/003-pool-idle-timeout/spec.md.

Adds 'Connection Idle Timeout' keyword (synonym: 'Pool Idle Timeout') exposed via SqlConnectionStringBuilder.IdleTimeout. When > 0, connections that have sat idle in the pool longer than the configured number of seconds are discarded on retrieval and a fresh connection is returned. Default 0 (disabled) matches the existing convention used by LoadBalanceTimeout and ConnectionLifetime.

Covers both pool designs (ChannelDbConnectionPool, WaitHandleDbConnectionPool).

Deferred to follow-up: proactive timer sweep (FR-008, FR-010) which the spec assumes is built on top of the pruning feature (#37338).
Copilot AI review requested due to automatic review settings May 19, 2026 10:11
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board May 19, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new pooling-related connection-string keyword, Connection Idle Timeout (synonym: Pool Idle Timeout), enabling lazy eviction of pooled connections that have sat idle longer than the configured number of seconds. This targets stale/half-open pooled connections (e.g., behind firewalls/load balancers) by discarding expired idle connections on the retrieval path in both pool implementations.

Changes:

  • Introduces Connection Idle Timeout parsing + SqlConnectionStringBuilder.IdleTimeout property (default 0 disables).
  • Tracks per-connection idle timestamp (DbConnectionInternal.IdleSinceUtc) and stamps it on return-to-pool; evicts idle-expired connections on retrieval in both pool designs.
  • Adds unit/functional tests for the new builder keyword/property and Channel pool idle-expiry behavior.

Reviewed changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml Adds XML doc snippet for SqlConnectionStringBuilder.IdleTimeout.
src/Microsoft.Data.SqlClient/ref/Microsoft.Data.SqlClient.cs Updates reference assembly surface with IdleTimeout property.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringKeywords.cs Adds canonical keyword string Connection Idle Timeout.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringDefaults.cs Adds default IdleTimeout = 0.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/ConnectionString/DbConnectionStringSynonyms.cs Adds synonym pool idle timeout.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs Adds IdleSinceUtc tracking + MarkPooledIdle() stamping helper.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/ChannelDbConnectionPool.cs Stamps idle time on return and adds idle-expiry check in IsLiveConnection.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolOptions.cs Adds IdleTimeout option (as TimeSpan) to pool group options.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs Stamps idle time on return and adds IsIdleExpired check at retrieval sites.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs Wires parsed idle-timeout option into pool group options creation.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionOptions.cs Parses/validates idle-timeout integer from connection string.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs Adds IdleTimeout keyword/property support + synonym mapping.
src/Microsoft.Data.SqlClient/src/Resources/Strings.resx Adds localized description string for the new keyword/property.
src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs Regenerates resource accessor for DbConnectionString_IdleTimeout.
src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/ChannelDbConnectionPoolTest.cs Adds unit tests for Channel pool idle-timeout behavior and stamping.
src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs Adds functional tests for keyword parsing, round-trip, default, and invalid values.
Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Language not supported
Comments suppressed due to low confidence (2)

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/ChannelDbConnectionPool.cs:445

  • The comment says that when IdleSinceUtc is the default (DateTime.MinValue) the idle-timeout check is a no-op and indicates the connection has never been pooled. In this PR IdleSinceUtc is initialized to CreateTime in DbConnectionInternal, so it will not be DateTime.MinValue, and even if it were, the current comparison would not be a no-op. Please update/remove this comment to match the actual semantics (e.g., describe the create-time initialization and that the check applies to any connection read from the idle channel).
            // Connection has been sitting idle longer than the configured idle timeout.
            // IdleSinceUtc is stamped by ReturnInternalConnection on each return; if it is the default
            // (DateTime.MinValue), the connection has never been pooled yet and the check is a no-op.
            TimeSpan idleTimeout = PoolGroupOptions.IdleTimeout;

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs:1351

  • Idle-timeout enforcement was added to the legacy WaitHandleDbConnectionPool (new IsIdleExpired check + MarkPooledIdle stamping), but there doesn’t appear to be any unit test coverage exercising this path (existing idle-timeout unit tests are only for ChannelDbConnectionPool). Please add at least one focused test validating that an idle-expired connection is discarded and replaced in WaitHandleDbConnectionPool, and that IdleTimeout==0 leaves behavior unchanged.
        /// <summary>
        /// Returns true when the supplied connection has been sitting idle in the pool longer than the
        /// configured <see cref="DbConnectionPoolGroupOptions.IdleTimeout"/>. Returns false when idle timeout
        /// is disabled (zero).
        /// </summary>
        private bool IsIdleExpired(DbConnectionInternal obj)
        {
            TimeSpan idleTimeout = PoolGroupOptions.IdleTimeout;
            return idleTimeout != TimeSpan.Zero && DateTime.UtcNow > obj.IdleSinceUtc + idleTimeout;
        }

@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

❌ Patch coverage is 91.35802% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.58%. Comparing base (bfbdd30) to head (5b1bbe9).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...lient/ConnectionPool/WaitHandleDbConnectionPool.cs 88.00% 3 Missing ⚠️
...qlClient/ConnectionPool/DbConnectionPoolOptions.cs 80.00% 2 Missing ⚠️
...c/Microsoft/Data/SqlClient/SqlConnectionOptions.cs 71.42% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4295      +/-   ##
==========================================
- Coverage   66.69%   64.58%   -2.11%     
==========================================
  Files         284      279       -5     
  Lines       43238    66146   +22908     
==========================================
+ Hits        28836    42721   +13885     
- Misses      14402    23425    +9023     
Flag Coverage Δ
CI-SqlClient ?
PR-SqlClient-Project 64.58% <91.35%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Fix stale comment in ChannelDbConnectionPool.IsLiveConnection: IdleSinceUtc
  is initialized to CreateTime, not DateTime.MinValue.
- Add WaitHandleDbConnectionPoolIdleTimeoutTest mirroring the existing
  channel-pool idle-timeout coverage (stamp on return, zero disables expiry,
  expired connection is replaced, fresh connection is reused).
@priyankatiwari08 priyankatiwari08 marked this pull request as ready for review May 21, 2026 11:20
@priyankatiwari08 priyankatiwari08 requested a review from a team as a code owner May 21, 2026 11:20
Copilot AI review requested due to automatic review settings May 21, 2026 11:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 17 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Language not supported

@priyankatiwari08 priyankatiwari08 added this to the 7.1.0-preview2 milestone May 21, 2026
- Skip MarkPooledIdle on return when IdleTimeout == TimeSpan.Zero so the
  default config has no per-return DateTime.UtcNow on the hot path. Applies
  to ChannelDbConnectionPool.ReturnInternalConnection and
  WaitHandleDbConnectionPool.PutNewObject.
- Stamp IdleSinceUtc when returning a connection into the transacted pool
  (WaitHandleDbConnectionPool.DeactivateObject before
  TransactedConnectionPool.PutTransactedObject) so idle expiry on the next
  retrieval measures time spent parked in the transacted pool, not time
  since create-time / last general-pool return.
- Add 2 WaitHandle pool tests covering the new behavior:
  IdleTimeout_TransactedPool_StampsOnReturn and
  IdleTimeout_Zero_DoesNotStampOnReturn.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 17 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Language not supported
Comments suppressed due to low confidence (2)

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs:1043

  • The idle-timeout eviction check is evaluated after obj.IsConnectionAlive(). For long-idle pooled connections, IsConnectionAlive() may perform an expensive SNI-level liveness probe; if the connection is already idle-expired, that work is unnecessary. Consider checking IsIdleExpired(obj) first (or reordering the condition) so expired connections are discarded without doing a liveness check.

This issue also appears on line 1218 of the same file.

                                if ((obj != null) && (!obj.IsConnectionAlive() || IsIdleExpired(obj)))
                                {
                                    SqlClientEventSource.Log.TryPoolerTraceEvent("<prov.DbConnectionPool.GetConnection|RES|CPOOL> {0}, Connection {1}, found dead and removed.", Id, obj.ObjectID);
                                    DestroyObject(obj);
                                    obj = null;     // Setting to null in case creating a new object fails

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs:1222

  • Similar to the general-pool path: in the transacted-pool retrieval, the code calls obj.IsConnectionAlive() before IsIdleExpired(obj). Since IsConnectionAlive() can trigger an SNI liveness probe for idle connections, consider checking IsIdleExpired(obj) first to avoid extra work when the idle-timeout policy is what causes the connection to be recycled.
                    else if (!obj.IsConnectionAlive() || IsIdleExpired(obj))
                    {
                        SqlClientEventSource.Log.TryPoolerTraceEvent("<prov.DbConnectionPool.GetFromTransactedPool|RES|CPOOL> {0}, Connection {1}, found dead and removed.", Id, obj.ObjectID);
                        DestroyObject(obj);
                        obj = null;

@paulmedynski paulmedynski self-assigned this May 21, 2026
@paulmedynski paulmedynski added the Area\Connection Pooling Use this label to tag issues that apply to problems with connection pool. label May 21, 2026
@paulmedynski paulmedynski moved this from To triage to In review in SqlClient Board May 21, 2026
@mdaigle mdaigle self-assigned this May 21, 2026
@github-project-automation github-project-automation Bot moved this from In review to Waiting for customer in SqlClient Board May 22, 2026
…sacted idle handling

- Default Connection Idle Timeout 0 -> 300 (5 min, matches Npgsql); 0 disables.

- Remove 'Pool Idle Timeout' synonym; the canonical keyword is the only accepted form.

- Make idleTimeout a required parameter on DbConnectionPoolGroupOptions; defaults now live in DbConnectionStringDefaults.

- Use TimeSpan.FromSeconds for the ctor body conversion.

- WaitHandle pool: drop MarkPooledIdle() on transacted-pool return and remove the idle-expiry check on transacted-pool retrieval (transacting connections must never be proactively closed).

- WaitHandle pool: reorder general-pool retrieval to check idle expiry before the liveness probe; derive _cleanupWait from IdleTimeout when set.

- Channel pool: reorder IsLiveConnection so the idle check runs before IsConnectionAlive().

- Tests, doc snippet, and release notes updated accordingly.
@priyankatiwari08
Copy link
Copy Markdown
Contributor Author

All review feedback has been addressed:

  • Default value for Connection Idle Timeout is now 300 (5 min, matches Npgsql); 0 disables idle expiration.
  • The Pool Idle Timeout synonym has been removed; only the canonical keyword is accepted.
  • idleTimeout is now a required parameter in DbConnectionPoolGroupOptions.
  • The constructor uses TimeSpan.FromSeconds as suggested.
  • WaitHandle pool: dropped MarkPooledIdle() on transacted-pool return and removed idle-expiry check on transacted-pool retrieval (transacting connections are never proactively closed).
  • WaitHandle pool: general-pool retrieval now checks idle expiry before liveness; _cleanupWait is driven by IdleTimeout (random fallback when 0).
  • Channel pool: IsLiveConnection now checks idle expiry before liveness.
  • All affected tests and docs updated; release notes entry added.
  • All unit and functional tests pass (except 5 pre-existing AlwaysEncrypted admin-rights failures).

Ready for re-review. Please confirm if any further changes are needed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 18 changed files in this pull request and generated 5 comments.

Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Language not supported

Copy link
Copy Markdown
Contributor

@mdaigle mdaigle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making those changes. I have a few more updates that I'd like to see. Otherwise it's very close.

Comment thread release-notes/7.1/7.1.0-preview1.md Outdated
Comment thread release-notes/7.1/7.1.0-preview1.md Outdated
Comment thread release-notes/7.1/7.1.0-preview1.md Outdated
Comment thread doc/snippets/Microsoft.Data.SqlClient/SqlConnectionStringBuilder.xml Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 20 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Language not supported
Comments suppressed due to low confidence (1)

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs:138

  • The XML doc comment for UseOverallConnectTimeoutForPoolWaitString is malformed (it closes without an opening ). With TreatWarningsAsErrors enabled, this can fail the build with an XML-doc warning (CS1570).
    /// The name of the app context switch that controls whether pool operations
    /// should count against the caller's overall ConnectTimeout budget.
    /// </summary>
    private const string UseOverallConnectTimeoutForPoolWaitString =
        "Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWait";

Comment on lines 191 to 195
SetSwitchValue(
"s_useLegacyIdleTimeoutBehavior",
_useLegacyIdleTimeoutBehaviorOriginal);
"s_useOverallConnectTimeoutForPoolWait",
_useOverallConnectTimeoutForPoolWaitOriginal);
Comment on lines +344 to 348
public bool? UseLegacyIdleTimeoutBehavior
{
get => GetSwitchValue("s_useLegacyIdleTimeoutBehavior");
set => SetSwitchValue("s_useLegacyIdleTimeoutBehavior", value);
/// Get or set the UseOverallConnectTimeoutForPoolWait switch value.
@priyankatiwari08 priyankatiwari08 marked this pull request as draft June 4, 2026 12:55
The 'accept both' merge resolution dropped a SetSwitchValue( token in Dispose()
and a closing brace plus /// <summary> between UseLegacyIdleTimeoutBehavior and
UseOverallConnectTimeoutForPoolWait, causing CS1002/CS1513 compile errors.
The 'accept both' merge dropped the opening /// <summary> line on three
UseOverallConnectTimeoutForPoolWait XML doc comments (const string,
cached SwitchValue field, and public property), leaving them malformed.
Copilot AI review requested due to automatic review settings June 4, 2026 15:03
@priyankatiwari08 priyankatiwari08 marked this pull request as ready for review June 4, 2026 15:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 20 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Language not supported

@priyankatiwari08 priyankatiwari08 marked this pull request as draft June 5, 2026 07:42
WaitHandleDbConnectionPoolBudgetTest was added in main while this branch
was in flight; updating its DbConnectionPoolGroupOptions construction to
pass idleTimeout: 0 fixes the CS7036 net462 build error.
…nPoolGroupOptions in new idle-timeout tests

Main added a TimeoutTimer parameter to ChannelDbConnectionPool.TryGetConnection
and WaitHandleDbConnectionPool.TryGetConnection while this branch was in flight.
The new idle-timeout tests still used the old 3-arg form, causing CS7036 on net9.0.
Also missed one DbConnectionPoolGroupOptions ctor call in ConcurrentCallers test.
Copilot AI review requested due to automatic review settings June 5, 2026 08:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Language not supported

Comment on lines +989 to +1001
<remarks>
<para>
This property corresponds to the "Connection Idle Timeout" key within the connection string.
</para>
<para>
The driver makes a best effort to discard connections that have remained idle in the pool for longer than this value. The exact point in the connection lifecycle at which the check occurs is an implementation detail and may change over time. This protects callers from receiving connections that may have been silently closed by firewalls, load balancers, or server-side inactivity thresholds.
</para>
<para>
A value of zero (0) disables idle expiration; connections are kept in the pool indefinitely (subject to other expiry rules such as <see cref="P:Microsoft.Data.SqlClient.SqlConnectionStringBuilder.LoadBalanceTimeout" />).
</para>
<para>
Idle timeout operates independently of <see cref="P:Microsoft.Data.SqlClient.SqlConnectionStringBuilder.LoadBalanceTimeout" />. Whichever threshold is exceeded first causes the connection to be discarded.
</para>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rightly pointed. Added in document

Comment thread src/Microsoft.Data.SqlClient/src/Resources/Strings.resx
@priyankatiwari08 priyankatiwari08 marked this pull request as ready for review June 5, 2026 09:16
priyankatiwari08 added a commit to priyankatiwari08/SqlClient that referenced this pull request Jun 5, 2026
…ehavior switch and tighten idle-timeout test coverage

- Delete redundant IdleTimeout_DefaultIsZero_DisablesExpiry from ChannelDbConnectionPoolTest. The 'default' framing was misleading (the builder-layer default is 300, not 0) and the zero-as-argument path is already covered by IdleTimeout_PoolGroupOptions_ConvertsSecondsToTimeSpan and IdleTimeout_Zero_DoesNotExpire.

- Add IdleTimeout_LegacySwitch_SuppressesEviction to both ChannelDbConnectionPoolTest and WaitHandleDbConnectionPoolIdleTimeoutTest. Flips UseLegacyIdleTimeoutBehavior=true via LocalAppContextSwitchesHelper, back-dates ReturnedTime well past the 1-second timeout, and asserts the connection is still reused. Closes the coverage gap on switch gating in both pool implementations.

- Document the gating in the public surfaces: extend SqlConnectionStringBuilder.xml <remarks> with a paragraph describing the Switch.Microsoft.Data.SqlClient.UseLegacyIdleTimeoutBehavior AppContext switch (defaults to true), and the three opt-out mechanisms (AppContext.SetSwitch, <RuntimeHostConfigurationOption>, runtimeconfig.json). Mirror the gating note in DbConnectionString_IdleTimeout in Strings.resx and the auto-generated Strings.Designer.cs accessor so the [ResDescription] surfaced in property grids matches.
priyankatiwari08 added a commit to priyankatiwari08/SqlClient that referenced this pull request Jun 5, 2026
…ehavior switch and tighten idle-timeout test coverage

- Delete redundant IdleTimeout_DefaultIsZero_DisablesExpiry from ChannelDbConnectionPoolTest. The 'default' framing was misleading (the builder-layer default is 300, not 0) and the zero-as-argument path is already covered by IdleTimeout_PoolGroupOptions_ConvertsSecondsToTimeSpan and IdleTimeout_Zero_DoesNotExpire.

- Add IdleTimeout_LegacySwitch_SuppressesEviction to both ChannelDbConnectionPoolTest and WaitHandleDbConnectionPoolIdleTimeoutTest. Flips UseLegacyIdleTimeoutBehavior=true via LocalAppContextSwitchesHelper, back-dates ReturnedTime well past the 1-second timeout, and asserts the connection is still reused. Closes the coverage gap on switch gating in both pool implementations.

- Document the gating in the public surfaces: extend SqlConnectionStringBuilder.xml <remarks> with a paragraph describing the Switch.Microsoft.Data.SqlClient.UseLegacyIdleTimeoutBehavior AppContext switch (defaults to true), and the three opt-out mechanisms (AppContext.SetSwitch, <RuntimeHostConfigurationOption>, runtimeconfig.json). Mirror the gating note in DbConnectionString_IdleTimeout in Strings.resx and the auto-generated Strings.Designer.cs accessor so the [ResDescription] surfaced in property grids matches.
Copilot AI review requested due to automatic review settings June 5, 2026 13:08
@priyankatiwari08 priyankatiwari08 force-pushed the feature/idle-connection-timeout-pr1 branch from 7b13305 to 126e272 Compare June 5, 2026 13:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs: Language not supported

Comment on lines +237 to +238
long cleanupWaitMilliseconds = (long)idleTimeout.TotalMilliseconds / 2;
_cleanupWait = cleanupWaitMilliseconds >= int.MaxValue ? int.MaxValue : (int)cleanupWaitMilliseconds;
…ehavior switch and tighten idle-timeout test coverage

- Delete redundant IdleTimeout_DefaultIsZero_DisablesExpiry from ChannelDbConnectionPoolTest. The 'default' framing was misleading (the builder-layer default is 300, not 0) and the zero-as-argument path is already covered by IdleTimeout_PoolGroupOptions_ConvertsSecondsToTimeSpan and IdleTimeout_Zero_DoesNotExpire.

- Add IdleTimeout_LegacySwitch_SuppressesEviction to both ChannelDbConnectionPoolTest and WaitHandleDbConnectionPoolIdleTimeoutTest. Flips UseLegacyIdleTimeoutBehavior=true via LocalAppContextSwitchesHelper, back-dates ReturnedTime well past the 1-second timeout, and asserts the connection is still reused. Closes the coverage gap on switch gating in both pool implementations.

- Document the gating in the public surfaces: extend SqlConnectionStringBuilder.xml <remarks> with a paragraph describing the Switch.Microsoft.Data.SqlClient.UseLegacyIdleTimeoutBehavior AppContext switch (defaults to true), and the three opt-out mechanisms (AppContext.SetSwitch, <RuntimeHostConfigurationOption>, runtimeconfig.json). Mirror the gating note in DbConnectionString_IdleTimeout in Strings.resx and the auto-generated Strings.Designer.cs accessor so the [ResDescription] surfaced in property grids matches.
@priyankatiwari08 priyankatiwari08 force-pushed the feature/idle-connection-timeout-pr1 branch from 126e272 to 0cf4d4a Compare June 5, 2026 13:19
long cleanupWaitMilliseconds = (long)idleTimeout.TotalMilliseconds / 2;
_cleanupWait = cleanupWaitMilliseconds >= int.MaxValue ? int.MaxValue : (int)cleanupWaitMilliseconds;
}
else
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid duplicating the calculation and move this condition up to the first block:

if (LocalAppContextSwitches.UseLegacyIdleTimeoutBehavior || idleTimeout == TimeSpan.Zero)
{
  // Historical calculation.
}
else
{
  // Use new Idle Timeout value.
}

Note that your changes here eliminate the "None" state I discussed earlier - this old pool will always perform idle connection cleanup, despite the connection string option claiming that a value of 0 means idle cleanup is disabled.

PoolGroupOptions.IdleTimeout != TimeSpan.Zero)
{
obj.MarkPooledIdle();
obj.ReturnedToPool();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... so now we're in a situation where the pool is 100% returning this connection to the idle pool, but we're not calling ReturnedToPool(), which seems wrong based on the context here and method name.

Maybe a less-general method name like SetReturnedTime() would be better, since that's exactly what we want the connection to do. The connection is responsible for knowing what sort of time to use, and the pool is responsible for telling the connection to set it. I think that keeps our mechanism/policy separation, and makes the calling code clearer. Thoughts?

@github-project-automation github-project-automation Bot moved this from In progress to Waiting for customer in SqlClient Board Jun 5, 2026
priyankatiwari08 added a commit to priyankatiwari08/SqlClient that referenced this pull request Jun 5, 2026
…ryGetConnection in shutdown tests

PR dotnet#4295 (merged to main) added a required TimeoutTimer parameter to ChannelDbConnectionPool.TryGetConnection. The shutdown tests added in this PR still call the pre-dotnet#4295 3-arg overload, which compiles locally against PoolShutdown's older base but fails in the CI pipeline because the pipeline merges this PR's head into the post-dotnet#4295 main. Pass TimeoutTimer.StartNew(TimeSpan.FromSeconds(15)) at all 5 call sites to match the new signature.
@mdaigle mdaigle moved this from Waiting for customer to In review in SqlClient Board Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area\Connection Pooling Use this label to tag issues that apply to problems with connection pool. Author attention needed PRs that require author to respond or make updates to PR.

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

4 participants