Skip to content

Extract pool blocking-period error state into BlockingPeriodErrorState#4395

Merged
mdaigle merged 19 commits into
mainfrom
dev/mdaigle/pool-blocking-period-refactor
Jul 13, 2026
Merged

Extract pool blocking-period error state into BlockingPeriodErrorState#4395
mdaigle merged 19 commits into
mainfrom
dev/mdaigle/pool-blocking-period-refactor

Conversation

@mdaigle

@mdaigle mdaigle commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

This is Part 1 of 3 splitting #4376 ("Dev/mdaigle/pool rate limit") into stacked, reviewable PRs.

This PR extracts the connection pool's blocking-period (error backoff) logic out of WaitHandleDbConnectionPool into a reusable, testable BlockingPeriodErrorState class. This keeps the pool's connection-acquisition path focused on capacity/queue concerns. Part 2 will use the new class to implement blocking period support in the ChannelDbConnectionPool.

The pool blocking period follows this state machine:
image

The pool calls Enter() any time blocking is enabled and an error occurs while opening a connection. This puts the pool in the blocked state and blocks future requests from attempting an open until the period ends. Subsequent errors double the blocking period (up to a 60s max). Successful connections reset the error state and blocking period.

To show that nothing changed for the existing pool, I added new unit tests and applied them selectively in a separate branch. If these pass, then the refactors have not impacted behavior: #4411

Changes

  • New BlockingPeriodErrorState — encapsulates cached-exception fast-fail, exponential backoff (5s → 60s cap), exit timer, and synchronization. Takes an injectable TimeProvider so timer scheduling is deterministic in tests.
  • WaitHandleDbConnectionPool — refactored to use BlockingPeriodErrorState instead of inline error-state fields/logic.
  • DbConnectionPoolGroup.IsBlockingPeriodEnabled() — new helper centralizing the PoolBlockingPeriod decision (Auto → not an Azure SQL endpoint, AlwaysBlock → true, NeverBlock → false). Consumed by Part 2.
  • ADP.UnsafeCreateTimer(TimeProvider, ...) — new overload returning ITimer that suppresses ExecutionContext flow while honoring the injected TimeProvider; required by BlockingPeriodErrorState.
  • BlockingPeriodErrorStateTest — unit tests using FakeTimeProvider (29 tests).

Stacking

  • Part 1 (this PR) → main
  • Part 2 (channel-pool rate limiting) → this branch
  • Part 3 (GitHub instructions) → Part 2

Checklist

  • Tests added (29 passing via FakeTimeProvider)
  • No public API changes
  • No breaking changes
  • Verified against customer repro (n/a — internal refactor)

Move the connection pool's blocking-period (error backoff) logic out of WaitHandleDbConnectionPool into a reusable, testable BlockingPeriodErrorState class with exponential backoff (5s..60s), cached-exception fast-fail, and an injectable TimeProvider for deterministic tests. Add DbConnectionPoolGroup.IsBlockingPeriodEnabled() and the ADP.UnsafeCreateTimer(TimeProvider,...) overload it depends on. Includes BlockingPeriodErrorStateTest.
Copilot AI review requested due to automatic review settings June 23, 2026 17:24
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Jun 23, 2026

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

Refactors the legacy wait-handle connection pool’s blocking-period (error backoff) logic into a dedicated BlockingPeriodErrorState component, adds a pool-group helper for determining when blocking is enabled, and introduces a TimeProvider-based timer factory to enable deterministic unit testing.

Changes:

  • Added BlockingPeriodErrorState (cached exception + exponential backoff + exit timer) and corresponding unit tests using FakeTimeProvider.
  • Refactored WaitHandleDbConnectionPool to delegate blocking-period logic to the new state object and moved the blocking-period enablement decision into DbConnectionPoolGroup.
  • Added an ADP.UnsafeCreateTimer(TimeProvider, ...) overload returning ITimer to support TimeProvider-driven timers.

Reviewed changes

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

Show a summary per file
File Description
src/Microsoft.Data.SqlClient/tests/UnitTests/ConnectionPool/BlockingPeriodErrorStateTest.cs Adds comprehensive unit tests for the new blocking-period state logic using FakeTimeProvider.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/WaitHandleDbConnectionPool.cs Replaces inlined error/backoff fields and timer logic with BlockingPeriodErrorState.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/DbConnectionPoolGroup.cs Centralizes the PoolBlockingPeriod decision into IsBlockingPeriodEnabled().
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ConnectionPool/BlockingPeriodErrorState.cs Introduces the new reusable blocking-period error state implementation.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs Adds a TimeProvider-aware UnsafeCreateTimer overload returning ITimer.

Comment thread src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs Outdated
@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.02985% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.97%. Comparing base (c30bbbc) to head (926ed13).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
...lClient/ConnectionPool/BlockingPeriodErrorState.cs 96.87% 3 Missing ⚠️
...SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs 75.00% 2 Missing ⚠️
...lient/ConnectionPool/WaitHandleDbConnectionPool.cs 90.47% 2 Missing ⚠️
.../SqlClient/ConnectionPool/DbConnectionPoolGroup.cs 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4395      +/-   ##
==========================================
- Coverage   65.78%   63.97%   -1.81%     
==========================================
  Files         286      283       -3     
  Lines       43696    66728   +23032     
==========================================
+ Hits        28745    42690   +13945     
- Misses      14951    24038    +9087     
Flag Coverage Δ
CI-SqlClient ?
PR-SqlClient-Project 63.97% <94.02%> (?)

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.

Comment thread src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs Outdated
@mdaigle
mdaigle marked this pull request as ready for review June 23, 2026 20:45
Copilot AI review requested due to automatic review settings June 23, 2026 20:45
@mdaigle
mdaigle requested a review from a team as a code owner June 23, 2026 20:45
@mdaigle mdaigle added this to the 7.1.0-preview2 milestone Jun 23, 2026

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

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

Comment thread src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs Outdated
Comment thread src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs Outdated
@github-project-automation github-project-automation Bot moved this from To triage to Waiting for customer in SqlClient Board Jun 24, 2026
Copilot AI review requested due to automatic review settings June 25, 2026 23:24

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

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

@paulmedynski paulmedynski 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.

Latest changes look good. Waiting for further offline discussion on my earlier comments.

Comment thread src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs Outdated
Comment thread .editorconfig Outdated

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

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Copilot AI review requested due to automatic review settings July 2, 2026 19:49

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

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

Copilot AI review requested due to automatic review settings July 8, 2026 01:12

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

Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.

@mdaigle
mdaigle merged commit 73b9a96 into main Jul 13, 2026
354 checks passed
@mdaigle
mdaigle deleted the dev/mdaigle/pool-blocking-period-refactor branch July 13, 2026 23:12
@github-project-automation github-project-automation Bot moved this from Waiting for customer to Done in SqlClient Board Jul 13, 2026
cheenamalhotra pushed a commit that referenced this pull request Jul 14, 2026
#4395)

* Extract pool blocking-period error state into BlockingPeriodErrorState

Move the connection pool's blocking-period (error backoff) logic out of WaitHandleDbConnectionPool into a reusable, testable BlockingPeriodErrorState class with exponential backoff (5s..60s), cached-exception fast-fail, and an injectable TimeProvider for deterministic tests. Add DbConnectionPoolGroup.IsBlockingPeriodEnabled() and the ADP.UnsafeCreateTimer(TimeProvider,...) overload it depends on. Includes BlockingPeriodErrorStateTest.

* Add comments

* Improve locking

* First round of review changes.

* Require exhaustive switch statements.

* Add wait handle pool unit tests for blocking period.

* Remove rule.

* Improve tests. Add TODOs.

* Update test names and xml.

* Add documentation about callback idempotency.

* Fix xml docs

* Add default switch case.

* Swallow errors. Fix disposal.

* Fix test conflicts

* Simplify enter/exit API.

* Restore original behavior.

* Revert editorconfig changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants