Skip to content

Add connection-creation rate limiting to ChannelDbConnectionPool#4396

Draft
mdaigle wants to merge 1 commit into
dev/mdaigle/pool-blocking-period-refactorfrom
dev/mdaigle/pool-channel-rate-limiting
Draft

Add connection-creation rate limiting to ChannelDbConnectionPool#4396
mdaigle wants to merge 1 commit into
dev/mdaigle/pool-blocking-period-refactorfrom
dev/mdaigle/pool-channel-rate-limiting

Conversation

@mdaigle

@mdaigle mdaigle commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

This is Part 2 of 3 splitting #4376 ("Dev/mdaigle/pool rate limit") into stacked, reviewable PRs. It stacks on #4395 (Part 1) — review/merge that first.

This PR adds an optional connection-creation rate-limiting policy to ChannelDbConnectionPool, decoupled from the blocking-period error state extracted in Part 1.

Changes

  • ChannelDbConnectionPool — when a System.Threading.RateLimiting.RateLimiter is configured, a new physical connection open requires a permit. If the permit is denied, the caller waits for an existing connection to be returned instead of forcing a second create. Leases are always released — including on a failed open — so the pool cannot starve future callers.
  • NoOpAcquiredLease — lightweight always-acquired lease used when no limiter is configured.
  • Package wiring — adds System.Threading.RateLimiting to Directory.Packages.props and references it from the product project plus the ManualTests/UnitTests projects.
  • Specspecs/006-pool-rate-limiting/ (spec + diagrams).
  • TestsChannelDbConnectionPoolTest covers permit-available, permit-denied/reuse, and lease-disposal-on-failure (91 tests passing).

Note: this PR also repairs two pre-existing build breaks in ChannelDbConnectionPoolTest that were present on the source branch (a dropped CountingSuccessfulConnectionFactory class declaration, and DbConnectionPoolGroupOptions calls missing the idleTimeout argument added on main).

Stacking

Checklist

  • Tests added (91 passing, sync + async paths)
  • No public API changes
  • No breaking changes
  • Verified against customer repro (n/a — new opt-in policy)

Introduce an optional System.Threading.RateLimiting policy that throttles new physical connection opens in the channel pool: when a permit is denied the caller waits for a returned connection instead of forcing a create, and leases are always released (including on failure) to avoid starvation. Adds NoOpAcquiredLease, wires the RateLimiting package into the product and test projects, and includes the 006-pool-rate-limiting spec. Also repairs two pre-existing build breaks in ChannelDbConnectionPoolTest (a dropped CountingSuccessfulConnectionFactory declaration and DbConnectionPoolGroupOptions calls missing the new idleTimeout argument).

Copilot AI left a comment

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.

Pull request overview

Adds opt-in connection-creation rate limiting to the v2 ChannelDbConnectionPool using System.Threading.RateLimiting.RateLimiter, plus introduces a lightweight always-acquired lease for the “no limiter configured” case. The PR also wires the new dependency via central package management, adds a feature spec/diagrams, and extends unit tests to cover rate limiting + blocking-period behaviors (stacked on Part 1 / #4395).

Changes:

  • Add optional RateLimiter integration to throttle physical connection creation in ChannelDbConnectionPool, with a NoOpAcquiredLease fallback.
  • Wire System.Threading.RateLimiting into product + test projects (and Directory.Packages.props).
  • Add spec + diagrams and expand ChannelDbConnectionPoolTest coverage for rate limiting and blocking-period behavior.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/ChannelDbConnectionPool.cs Adds optional rate-limiter gating for new physical opens and integrates blocking-period error state.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/NoOpAcquiredLease.cs Adds a singleton no-op acquired RateLimitLease for the “no limiter” path.
Directory.Packages.props Adds centralized package versions for System.Threading.RateLimiting.
src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj References System.Threading.RateLimiting for product build.
src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft.Data.SqlClient.UnitTests.csproj References System.Threading.RateLimiting for unit test compilation across TFMs.
src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTests.csproj References System.Threading.RateLimiting for manual test compilation across TFMs.
src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/ChannelDbConnectionPoolTest.cs Adds/repairs tests covering blocking-period behavior and rate-limiter permit/lease handling.
specs/006-pool-rate-limiting/spec.md Documents requirements and acceptance scenarios for rate limiting + blocking period.
specs/006-pool-rate-limiting/diagrams.md Adds diagrams comparing existing vs. new rate-limiting flow.

Comment on lines +525 to +530
if (leaseAcquired &&
_connectionCreationRateLimiter is not null &&
_connectionSlots.ReservationCount < MaxPoolSize)
{
_idleChannel.TryWrite(null);
}
Comment on lines +554 to +558
catch (Exception ex) when (ADP.IsCatchableExceptionType(ex))
{
// Enter the blocking period error state on creation failure if configured.
// FR-006, FR-007.
_errorState?.Enter(ex);
Comment on lines +466 to +468
// its rate-limit lease (see finally below). We prefer to recycle existing
// connections rather then queue on the rate limit. When no limiter is
// configured we substitute a no-op acquired lease.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To triage

Development

Successfully merging this pull request may close these issues.

2 participants