Interview question
Diagnose connection-pool pressure from a leaking code path
Pairs a bounded isolated reproduction with telemetry and a disposal fix for leaked database connections.
TL;DR
Pairs a bounded isolated reproduction with telemetry and a disposal fix for leaked database connections.
Connection lifetime, pool saturation, disposal, concurrency reproduction, metrics, and mitigation versus root cause.
Practice the problem like a real interview: restate, reason, implement, and test.
The endpoint manually opens a database connection and returns early on one validation branch without closing it. In an isolated test database, configure a small pool, repeat that branch, and show a corrected await using scope. Do not stress the developer or production database.
Next in API Testing Labs: Readiness Check
Query duration remains low, but connection acquisition time and timeout count rise until the pool is exhausted. Fixing disposal restores steady active/idle connection behavior.
I separate evidence: fast database commands plus slow connection acquisition points to pool pressure rather than query execution. The code fix makes ownership explicit with await using, including early returns and exceptions.
[Fact]
public async Task Leaked_branch_exhausts_a_small_pool_but_disposal_recovers()
{
await using var database = await PostgresFixture.StartAsync(
maxPoolSize: 2,
connectionTimeoutSeconds: 1);
var leaked = new List<DbConnection>();
try
{
leaked.Add(await OpenAndReturnEarlyAsync(database.DataSource));
leaked.Add(await OpenAndReturnEarlyAsync(database.DataSource));
await Assert.ThrowsAsync<NpgsqlException>(async () =>
await database.DataSource.OpenConnectionAsync());
}
finally
{
foreach (var connection in leaked)
await connection.DisposeAsync();
}
var correctedCalls = Enumerable.Range(0, 20)
.Select(_ => ExecuteHealthyBranchAsync(database.DataSource));
await Task.WhenAll(correctedCalls).WaitAsync(TimeSpan.FromSeconds(10));
Assert.Equal(0, database.CheckedOutConnections);
}
// Deliberately broken reproduction: an early return transfers no ownership
// and leaves the opened connection checked out.
private static async Task<DbConnection> OpenAndReturnEarlyAsync(
DbDataSource dataSource) =>
await dataSource.OpenConnectionAsync();
private static async Task ExecuteHealthyBranchAsync(DbDataSource dataSource)
{
await using var connection = await dataSource.OpenConnectionAsync();
await using var command = connection.CreateCommand();
command.CommandText = "SELECT 1";
await command.ExecuteScalarAsync();
}
The fixture must use a disposable PostgreSQL instance and expose pool metrics only to the test. The failing half proves the acquisition timeout; the corrected half proves that deterministic disposal restores the pool under repeated use.
The production evidence chain is request concurrency, connection acquisition duration, active/idle pool counts, database sessions, and recent code changes. A focused isolated load test can prove the fix; increasing pool size alone only delays exhaustion.
Share the question with a concise Core-answer excerpt and invite other developers to add their perspective.
Help improve the interview library.
Say thanks with a standalone, one-time $5 contribution. No account required.
Aporeon is shaped by Aleksandar Tomovski, a software developer with experience on both sides of technical interviews. Content is reviewed for accuracy, natural spoken delivery, useful depth, and honest trade-offs.