NpgsqlDatabaseCreator.Exist doesn't like DbConnectionInterceptor to open the connection

Aperta
#3,455 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
25/100
Tipo di issue
Bug
Chiarezza
Da chiarire
Stato di attività
Ferma
Stack tecnologico
csharp, postgresql
Ambito
backend, databases

Direzione di ricerca

Start by reading the linked EF Core RelationalConnection.cs lines 758–767 and the referenced pull request #3349, then run the issue’s interceptor repro. The issue describes repeated ExistsAsync calls leaving the connection open and failing on the second call; done would mean the interceptor lifecycle behaves as expected and repeated calls no longer fail.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

We somehow had a DbConnectionInterceptor that opens a connection on ConnectionOpening. I thought it could be done

In EF Core, ConnectionOpened is invoked regardless of IsSuppressed value, so the interceptor should've opened the connection when IsSuppressed is true.
https://github.com/dotnet/efcore/blob/6cacf97e1093965928d27e99a7b3f90d25c0b01b/src/EFCore.Relational/Storage/RelationalConnection.cs#L758-L767

But after this change (https://github.com/npgsql/efcore.pg/pull/3349), we had errors (reproduced below) and connection leaks (couldn't reproduce in the test).

Here's the repro:

public sealed class TestContext : DbContext
{
    public TestContext(DbContextOptions<TestContext> options)
        : base(options)
    {
    }
}

public sealed class ConnectionOpeningInterceptor : DbConnectionInterceptor
{
    public override async ValueTask<InterceptionResult> ConnectionOpeningAsync(
        DbConnection connection, ConnectionEventData eventData, InterceptionResult result,
        CancellationToken cancellationToken = default)
    {
        await connection.OpenAsync(cancellationToken);
        return InterceptionResult.Suppress();
    }
}

var services = new ServiceCollection();
services.AddDbContext<TestContext>(options =>
{
    options.UseNpgsql("connection string");
    options.AddInterceptors(new ConnectionOpeningInterceptor());
});

await using var serviceProvider = services.BuildServiceProvider();
var context = serviceProvider.GetRequiredService<TestContext>();
var relationalDatabaseCreator = context.GetService<IRelationalDatabaseCreator>();

await relationalDatabaseCreator.ExistsAsync(); // okay, but doesn't close connection
await relationalDatabaseCreator.ExistsAsync(); // throws exception on the second invocation

I think the change slightly broke the semantics of the interceptor.
Before the change, The invocation of ConnectionOpening was always followed by the matching invocations of ConnectionOpened and ConnectionClosing or ConnectionDisposing if there were no errors.
But after the change, there is always one more invocation of ConnectionOpening

We removed the interceptor, so it doesn't necessarily need to be fixed for me, but I leave this issue as a future note.

Lingua principale
C#
Stelle
1.8k
Fork
268
Merge medio
2h 35m
PR unite (30g)
136

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di npgsql/efcore.pg

Tutte le issue di npgsql/efcore.pg

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.