Hey Guys!
As You maybe know from C# 8, every class with implement interface IAsyncDisposable
can be disposed of with clause await using
. It’s looks pretty, modern, even very good IDE like Rider show tips Use await using
what harm could there be? The answer is everything.
In my case, it was a situation related to very popular ORM library EntityFramework Core, version for PostgreSQL (efcore.pg). I have some background services, lovely timers, which every X time send SQL data by RabbitMQ (broadcast message). In this kind of situation, the best solution for a way of creating DbContext is the factory pattern. IoC containers do not correct in that context ;-(, the life scope of instances are different than web api. After implementation of my code, my lovely Rider tell me “Patryk, why You don’t use await using on Your context? It should be in this way!” and I did it…
I start it, test, looks very well, so go my CI / CD process deploy it to pre-production env (fortunately I don’t use production yet :-)! ). After 2 hours everything crashed. Dispose method is a very important part of the framework, especially for the database. All my Postgres connections were not disposed correctly, If You work before with that database, You will know what happens (connections limit). In logs I saw only:
System.InvalidOperationException: An exception has been raised that is likely due to a transient failure.
---> Npgsql.PostgresException (0x80004005): 53300: sorry, too many clients already
at Npgsql.NpgsqlConnector.<>c__DisplayClass160_0.<g__ReadMessageLong|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Npgsql.NpgsqlConnector.<>c__DisplayClass160_0.<g__ReadMessageLong|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Npgsql.NpgsqlConnector.Authenticate(String username, NpgsqlTimeout timeout, Boolean async)
at Npgsql.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.ConnectorPool.AllocateLong(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.<>c__DisplayClass32_0.<g__OpenLong|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken) at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
Even close of my application docker container does not dispose of these connections. The serum for that was only restart of PostgreSQL service, connections were in very strange state (idle -> active -> idle, something related to data buffering). Obviously is probably bug occurred in EF core which can be fixed in a trivial way, but lesson must be learned. After removed await
keyword from using
, everything again works very well :-).
Conclusion
The await using
handle dispose mechanism, so is a very important part of libraries. In my case, it was related to connections with DB but in other cases, it can cause memory leaks, keep a handle to file etc.
Also not always IDE tell You true, if You don’t sure about new thing with is related to disposing clause or similar staff, think twice ;-).
Thansk for reading & have a good day!
ps. Github issue was also created, If you met with a similar problem, don’t forget about inform library author about it :-)!