Add automatic pool size reduction (pruning) to ChannelDbConnectionPool#4304
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an automatic “pruning” mechanism to ChannelDbConnectionPool (pool V2) to gradually reduce excess idle connections during low demand by sampling idle counts over time and pruning based on the median sample.
Changes:
- Introduces pruning state, sampling logic, and a one-shot timer callback to periodically evaluate and close excess idle connections.
- Wires pruning timer enable/disable behavior into connection add/remove paths and disposes the timer during pool shutdown.
- Adds a dedicated unit test suite validating pruning configuration, sampling/median behavior, floors (MinPoolSize), and shutdown behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/ChannelDbConnectionPool.cs | Implements the pruning timer, sampling window/median computation, and integrates timer lifecycle with pool growth/shrink/shutdown. |
| src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/ChannelDbConnectionPoolPruningTest.cs | Adds unit tests covering pruning timer creation/configuration, sampling/median pruning behavior, and shutdown semantics. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4304 +/- ##
==========================================
- Coverage 66.69% 64.61% -2.08%
==========================================
Files 284 280 -4
Lines 43238 66162 +22924
==========================================
+ Hits 28836 42750 +13914
- Misses 14402 23412 +9010
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
mdaigle
left a comment
There was a problem hiding this comment.
Would like to see some improvements to the tests, otherwise looks good!
Resolve conflict in ChannelDbConnectionPool.Shutdown(): integrate PoolPruner.Dispose() from upstream dotnet#4304 with the branch's idempotent shutdown sequence (CAS guard, State transition, channel completion, Clear() reuse, final drain). Pruner is disposed before the channel is completed and drained so a pruning tick cannot race with the final drain. PoolPruner.Dispose is idempotent and non-throwing.
…notes Per Malcolm's follow-up review, channel pool (pool v2) changes will be announced in preview 3. Removes: - The 'Automatic Pool Pruning and Shutdown for the Channel-Based Pool' section (What Changed / Who Benefits / Impact) from release-notes/7.1/7.1.0-preview2.md. - The matching 'Implemented pool shutdown for ChannelDbConnectionPool and added automatic pool size reduction (pruning) for the channel-based pool' bullet from CHANGELOG.md's Changed section. PRs #4302 and #4304 are no longer referenced in the preview2 notes.
* [v7.1.0-preview2] Release Notes and vBump * vBump in Versions.props, OneBranch pipelines, and CI/PR pipelines to v7.1.0-preview2 * Release notes for v7.1.0-preview2 * Docs: clarify FileVersion vs AssemblyVersion in per-package alignment note Address Paul's PR feedback: the phrase 'unchanged from 7.0.2' attached to both FileVersion and AssemblyVersion, making it sound like FileVersion was also unchanged. Split into two sentences so only AssemblyVersion is described as unchanged from 7.0.2. Applied across all 4 per-package 7.1.0-preview2 release-notes files (AzureKeyVaultProvider, Extensions.Azure, Extensions.Abstractions, Internal.Logging). * Docs: correct WAM broker attribution in 7.1.0-preview2 release notes Address review feedback on PR #4422: - Rewrite Extensions.Azure preview2 notes to document WAM broker support properly (removes false "no functional changes" claim and wrong "added in 7.0.2" pointer). WAM was added in 7.1.0-preview2 per PR #4288's milestone, not 7.0.2. - Remove WAM Broker Support section from core preview2 notes; WAM lives only in the Extensions.Azure package. - Drop Microsoft.Identity.Client / Microsoft.Identity.Client.Broker dependency-bump bullet from core preview2 notes and CHANGELOG; MSAL packages are referenced only by Extensions.Azure, not by core Microsoft.Data.SqlClient (which uses the Wilson IdentityModel stack). Keep the .NET 10 SDK bump (PR #4287) in the core notes. - Split CHANGELOG "Re-shipped" bullet so Extensions.Azure gets its own callout for the WAM addition; AKV, Extensions.Abstractions, and Internal.Logging remain grouped as alignment-only. * Docs: address Malcolm's review comments on pool timeout release notes - Drop 'pool v2' framing from Configurable Idle Connection Timeout section; frame the new keyword/property as applying to the existing connection pool as well (channel pool changes will be announced in preview 3). - Add Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWait AppContext switch details (default false, opt-in to true) to the Connection Timeout Now Propagates Through the Pool section, and reframe Who Benefits/Impact to lead with unchanged default behavior. * Docs: drop channel-based pool pruning/shutdown section from preview2 notes Per Malcolm's follow-up review, channel pool (pool v2) changes will be announced in preview 3. Removes: - The 'Automatic Pool Pruning and Shutdown for the Channel-Based Pool' section (What Changed / Who Benefits / Impact) from release-notes/7.1/7.1.0-preview2.md. - The matching 'Implemented pool shutdown for ChannelDbConnectionPool and added automatic pool size reduction (pruning) for the channel-based pool' bullet from CHANGELOG.md's Changed section. PRs #4302 and #4304 are no longer referenced in the preview2 notes.
Introduce a PoolPruner that periodically samples the pool's idle connection count and, once a sampling window completes, prunes the median number of idle connections. This lets the pool shrink back toward MinPoolSize after load subsides while avoiding over-pruning during brief lulls.
* [v7.1.0-preview2] Release Notes and vBump * vBump in Versions.props, OneBranch pipelines, and CI/PR pipelines to v7.1.0-preview2 * Release notes for v7.1.0-preview2 * Docs: clarify FileVersion vs AssemblyVersion in per-package alignment note Address Paul's PR feedback: the phrase 'unchanged from 7.0.2' attached to both FileVersion and AssemblyVersion, making it sound like FileVersion was also unchanged. Split into two sentences so only AssemblyVersion is described as unchanged from 7.0.2. Applied across all 4 per-package 7.1.0-preview2 release-notes files (AzureKeyVaultProvider, Extensions.Azure, Extensions.Abstractions, Internal.Logging). * Docs: correct WAM broker attribution in 7.1.0-preview2 release notes Address review feedback on PR #4422: - Rewrite Extensions.Azure preview2 notes to document WAM broker support properly (removes false "no functional changes" claim and wrong "added in 7.0.2" pointer). WAM was added in 7.1.0-preview2 per PR #4288's milestone, not 7.0.2. - Remove WAM Broker Support section from core preview2 notes; WAM lives only in the Extensions.Azure package. - Drop Microsoft.Identity.Client / Microsoft.Identity.Client.Broker dependency-bump bullet from core preview2 notes and CHANGELOG; MSAL packages are referenced only by Extensions.Azure, not by core Microsoft.Data.SqlClient (which uses the Wilson IdentityModel stack). Keep the .NET 10 SDK bump (PR #4287) in the core notes. - Split CHANGELOG "Re-shipped" bullet so Extensions.Azure gets its own callout for the WAM addition; AKV, Extensions.Abstractions, and Internal.Logging remain grouped as alignment-only. * Docs: address Malcolm's review comments on pool timeout release notes - Drop 'pool v2' framing from Configurable Idle Connection Timeout section; frame the new keyword/property as applying to the existing connection pool as well (channel pool changes will be announced in preview 3). - Add Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWait AppContext switch details (default false, opt-in to true) to the Connection Timeout Now Propagates Through the Pool section, and reframe Who Benefits/Impact to lead with unchanged default behavior. * Docs: drop channel-based pool pruning/shutdown section from preview2 notes Per Malcolm's follow-up review, channel pool (pool v2) changes will be announced in preview 3. Removes: - The 'Automatic Pool Pruning and Shutdown for the Channel-Based Pool' section (What Changed / Who Benefits / Impact) from release-notes/7.1/7.1.0-preview2.md. - The matching 'Implemented pool shutdown for ChannelDbConnectionPool and added automatic pool size reduction (pruning) for the channel-based pool' bullet from CHANGELOG.md's Changed section. PRs #4302 and #4304 are no longer referenced in the preview2 notes.
Description
Summary
Implements automatic pool size reduction for
ChannelDbConnectionPool(connection pool V2). When demand drops, excess idle connections are gradually closed based on observed usage patterns rather than reacting to instantaneous idle counts.Design
LoadBalanceTimeout / PruningIntervalsamples (defaults to 300s / 10s = 30 samples whenConnection Lifetimeis 0), clamped toMaxSampleSize(300).MinPoolSize.MinPoolSize >= MaxPoolSize, noPoolPruneris created.Architecture
Pruning logic is encapsulated in a dedicated
PoolPrunerclass (IDisposable):PoolPrunerowns the timer, sample buffer, and sampling/pruning logic.ChannelDbConnectionPoolholds a nullablePrunerauto-property —nullfor fixed-size pools.Pruner?.UpdateTimer()after connections are opened or closed.PruneConnections(int count)for the pruner to call back into.ChannelDbConnectionPoolimplementsIDisposable(delegates toShutdown()).Changes
PoolPruner.cs(new): Encapsulates all pruning state and logic — timer, sample buffer, median calculation, enable/disable, and disposal.ChannelDbConnectionPool.cs: AddedPoolPruner? Prunerauto-property,PruneConnections()callback method,IDisposableimplementation, and pruner creation in constructor.ChannelDbConnectionPoolPruningTest.cs(new): Unit tests for pruning behavior.Thread Safety
lock(_timer)to read/write shared sample state.Dispose()acquires the same lock with a_disposedguard to prevent double-disposal.UpdateTimer()checks_pool.IsRunningboth before and inside the lock to avoid post-shutdown races.IsRunningandMinPoolSizefloor on each iteration.ADP.UnsafeCreateTimerto avoid capturingExecutionContextonto the long-lived timer.Issues
AB#44848
Testing
Tests
ChannelDbConnectionPoolPruningTest.cs: 19 test methods (28 runtime cases including Theory data) covering:UpdateTimerenable/disable logicDivideRoundingUpcorrectness (7 cases)using var poolfor deterministic cleanup viaIDisposableGetPruner()helper eliminates null-forgiving operator noiseGuidelines
Please review the contribution guidelines before submitting a pull request: