Skip to content

Commit 4ffbff1

Browse files
authored
PruneIdleConnectors: consider broken and lifetime-exceeded connections as pruned (npgsql#5184)
Fixes npgsql#5180
1 parent 6672f39 commit 4ffbff1

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

src/Npgsql/PoolingDataSource.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -444,10 +444,9 @@ static void PruneIdleConnectors(object? state)
444444
connector != null)
445445
{
446446
if (pool.CheckIdleConnector(connector))
447-
{
448447
pool.CloseConnector(connector);
449-
toPrune--;
450-
}
448+
449+
toPrune--;
451450
}
452451
}
453452

test/Npgsql.Tests/PoolTests.cs

+44
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,50 @@ public async Task Prune_idle_connectors(int minPoolSize, int connectionIdleLifeT
203203
AssertPoolState(dataSource, open: Math.Max(1, minPoolSize), idle: Math.Max(0, minPoolSize - 1));
204204
}
205205

206+
[Test]
207+
[Explicit("Timing-based")]
208+
public async Task Prune_counts_max_lifetime_exceeded()
209+
{
210+
await using var dataSource = CreateDataSource(csb =>
211+
{
212+
csb.MinPoolSize = 0;
213+
// Idle lifetime 2 seconds, 2 samples
214+
csb.ConnectionIdleLifetime = 2;
215+
csb.ConnectionPruningInterval = 1;
216+
csb.ConnectionLifetime = 5;
217+
});
218+
219+
// conn1 will exceed max lifetime
220+
await using var conn1 = await dataSource.OpenConnectionAsync();
221+
222+
// make conn1 4 seconds older than the others, so it exceeds max lifetime
223+
Thread.Sleep(4000);
224+
225+
await using var conn2 = await dataSource.OpenConnectionAsync();
226+
await using var conn3 = await dataSource.OpenConnectionAsync();
227+
228+
await conn1.CloseAsync();
229+
await conn2.CloseAsync();
230+
AssertPoolState(dataSource, open: 3, idle: 2);
231+
232+
// wait for 1 sample
233+
Thread.Sleep(1000);
234+
// ConnectionIdleLifetime not yet reached.
235+
AssertPoolState(dataSource, open: 3, idle: 2);
236+
237+
// close conn3, so we can see if too many connectors get pruned
238+
await conn3.CloseAsync();
239+
240+
// wait for last sample + a bit more time for reliability
241+
Thread.Sleep(1500);
242+
243+
// ConnectionIdleLifetime reached
244+
// - conn1 should have been closed due to max lifetime (but this should count as pruning)
245+
// - conn2 or conn3 should have been closed due to idle pruning
246+
// - conn3 or conn2 should remain
247+
AssertPoolState(dataSource, open: 1, idle: 1);
248+
}
249+
206250
[Test, Description("Makes sure that when a waiting async open is is given a connection, the continuation is executed in the TP rather than on the closing thread")]
207251
public async Task Close_releases_waiter_on_another_thread()
208252
{

0 commit comments

Comments
 (0)