-
Notifications
You must be signed in to change notification settings - Fork 874
Open
Description
ObjectDisposedException in ManualResetEventSlim during runtime queries (latency-dependent race condition)
Environment
- Npgsql Version: 10.0.1
- .NET Version: 10.0
- PostgreSQL: Supabase (via
pooler.supabase.com- PgBouncer Transaction Mode) - OS: Windows 11
Description
We are experiencing ObjectDisposedException on ManualResetEventSlim.Reset() in NpgsqlConnector.ResetCancellation() during runtime database queries.
Critical finding: The error is latency-dependent and 100% reproducible:
- Low latency (5-20ms): Never fails (Azure EU → Supabase EU)
- High latency (100-300ms): Always fails (Turkey → Supabase EU)
This suggests a race condition where the timing window is only hit under high-latency conditions.
Stack Trace
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Threading.ManualResetEventSlim'.
at System.Threading.ManualResetEventSlim.Reset()
at Npgsql.Internal.NpgsqlConnector.ResetCancellation()
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
Minimal Reproduction (without EF Core)
using Npgsql;
// Connection to Supabase via PgBouncer Transaction Mode pooler
var connectionString = "Host=aws-0-eu-central-1.pooler.supabase.com;Database=postgres;Username=postgres.xxx;Password=xxx;Port=5432;SSL Mode=Require;Multiplexing=false";
// Simulate high-latency environment or run from location with >100ms latency to database
await using var conn = new NpgsqlConnection(connectionString);
await conn.OpenAsync();
// Run multiple parallel queries to increase race condition probability
var tasks = Enumerable.Range(0, 10).Select(async _ =>
{
await using var cmd = new NpgsqlCommand("SELECT 1", conn);
await cmd.ExecuteScalarAsync();
});
await Task.WhenAll(tasks); // ObjectDisposedException occurs here under high latencyFrequency
- Every query under high-latency conditions (100-300ms)
- Never under low-latency conditions (5-20ms)
- Deterministic, not random
Connection Details
- Supabase Pooler: PgBouncer in Transaction Mode (
pooler.supabase.com) - Multiplexing: Disabled (
Multiplexing=false) - SSL: Required
Attempted Workarounds (None Worked)
| Configuration | Result |
|---|---|
Pooling=false |
Still fails |
NoResetOnClose=true |
Still fails |
CancellationTimeout=0 |
Still fails |
Multiplexing=false |
Still fails |
| Upgrade 10.0.0 → 10.0.1 | Still fails |
Analysis
The error occurs in ResetCancellation() which calls ManualResetEventSlim.Reset(). Under high latency:
- Query execution takes longer due to network delay
- This appears to trigger Npgsql's internal cancellation/timeout mechanism
- A race condition occurs: one thread disposes
ManualResetEventSlimwhile another callsReset()
The latency dependency explains why:
- Production (low latency) never hits the timing window
- Remote development (high latency) consistently hits it
Related Issues
- ObjectDisposedException in ManualResetEventSlim when running dotnet ef database update with .NET 10 and Npgsql 10.0.0 efcore.pg#3699 - Same stack trace but only during EF Core migrations (design-time)
- Npgsql 7.0.2 blocks threads NpgsqlConnector.PerformUserCancellation causing connection pool exhaustion #5032 - Previous ManualResetEventSlim threading issues in 7.0.2
Additional Context
This issue affects all runtime queries, not just EF Core migrations. The EF Core issue #3699 specifically states "non-design time activities function" - our finding expands the scope significantly.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels