How can I diagnose intermittent connection pool exhaustion in EF Core when using connection resiliency retry strategies?
0 reputation · 04 Jun 2021, 13:18 UTC
0 reputation · 04 Jun 2021, 13:18 UTC
Diagnosing intermittent connection pool exhaustion in EF Core applications that rely on connection resiliency retry strategies is challenging because the execution strategy masks underlying pool limits by automatically retrying failed commands. This can make it unclear whether observed failures stem from transient errors or from exhausted pool resources.
When using the SQL Server provider with ConnectRetryCount=0 and EnableRetryOnFailure, the default pool size and limits are not directly exposed, and there is uncertainty about how to differentiate retries caused by transient faults from those caused by pool exhaustion without disabling resiliency. Understanding the exact conditions that trigger pool exhaustion requires visibility into pool usage and checkout times.
What metrics or diagnostics can be enabled to observe actual connection pool usage and checkout times in EF Core when connection resiliency is active? How can I distinguish between transient errors that trigger retries and genuine pool exhaustion events without disabling the execution strategy? Are there recommended ways to log or expose pool exhaustion occurrences while retaining the benefits of connection resiliency?
When EF Core’s connection resiliency (execution strategy) is enabled, transient faults trigger automatic retries. This masking can make it look like the failures are due to temporary glitches when, in fact, the underlying ADO.NET connection pool may be exhausted and connections are not being returned to the pool.
ConnectionOpened and ConnectionClosed under the Microsoft.EntityFrameworkCore.Database.Connection category (3).OnConfiguring:optionsBuilder.LogTo(
Console.WriteLine,
new[] { Microsoft.EntityFrameworkCore.DbLoggerCategory.Database.Name },
Microsoft.EntityFrameworkCore.LogLevel.Information);
RelationalEventId.ConnectionOpened and RelationalEventId.ConnectionClosed). This lets you see each time a connection is taken from or returned to the pool.ConnectionOpened lines appear without a matching ConnectionClosed for the same connection ID, or where the number of concurrent opens steadily climbs and plateaus at the pool’s maximum size.Max Pool Size (default 100) and no further ConnectionClosed events, the pool is exhausted. The execution strategy will then retry the command, which will appear in the logs as repeated CommandExecuted entries followed by another ConnectionOpened attempt.TimeoutException or SqlException with a message about pool limits). Those exceptions confirm that the retry strategy could not recover because the pool was truly exhausted.Could you confirm whether the observed failures include exceptions that explicitly indicate pool exhaustion (for example, a TimeoutException or SqlException whose message mentions pool limits or “max pool size reached”)? Knowing this would let us focus on adjusting pool size versus investigating other transient faults.
Use comments to ask for clarification. Post a solution as an answer.
26,525 reputation · 04 Jun 2021, 19:33 UTC
EF Core’s retry strategy keeps the original SqlConnection alive, so a burst of retries can silently fill the pool. From EF Core 7 onward the SqlConnectionPoolStats API exposes real‑time metrics that are not logged by EF Core itself.
var stats = SqlConnectionPoolStats.GetStats();
Console.WriteLine($"MaxPoolSize={stats.MaxPoolSize} Active={stats.ActiveConnections} Idle={stats.IdleConnections}");
Run that snippet in a background task or a health‑check endpoint while your app is under load. A spike in ActiveConnections that never recedes is a clear sign of exhaustion. Pair this with sys.dm_exec_connections on SQL Server to see the server‑side view and confirm that the pool’s MaxPoolSize is being hit.