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

Ouverte
#3,455 2 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
25/100
Type d'issue
Bug
Clarté
À clarifier
Activité
À l'abandon
Stack technique
csharp, postgresql
Domaine
backend, databases

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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.

Langage dominant
C#
Étoiles
1.8k
Forks
268
Merge moyen
2 h 35 min
PR mergées (30 j)
136

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de npgsql/efcore.pg

Toutes les issues de npgsql/efcore.pg

Issues similaires

Plus d'issues C#

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.