1

I have this piece of code in program.cs to initialize my pool with 5 connections in my .net6 application using postgres and Npgsql.

List<NpgsqlConnection> connections = new List<NpgsqlConnection>();

for (int i = 0; i < 5; i++)
{

    NpgsqlConnection connection = new NpgsqlConnection(connectionString);
    try
    {
        connection.Open(); // This actually opens the connection

    }
    catch (Exception e)
    {
        continue;
    }

    connections.Add(connection);
}
connections.ForEach(connection => { connection.Close(); });

the first attempt to creata a connection is always falis with a timeout


2024-01-11T19:54:53.7699503+09:00 40000374-0003-fc00-b63f-84710c7967bb [INF] Entity Framework Core "6.0.19" initialized '"DbContextClass"' using provider '"Npgsql.EntityFrameworkCore.PostgreSQL":"6.0.8"' with options: "CommandTimeout=15 " (d2805559)
2024-01-11T19:55:09.4702152+09:00 40000374-0003-fc00-b63f-84710c7967bb [ERR] An error occurred using the connection to database '"my_db"' on server '""'. (5fc3407c)
2024-01-11T19:55:09.5272113+09:00 40000374-0003-fc00-b63f-84710c7967bb [INF] A transient exception occurred during execution. The operation will be retried after 0ms."
""System.TimeoutException: The operation has timed out.
   at Npgsql.Util.NpgsqlTimeout.Check()
   at Npgsql.Util.NpgsqlTimeout.CheckAndGetTimeLeft()
   at Npgsql.Util.NpgsqlTimeout.CheckAndApply(NpgsqlConnector connector)
   at Npgsql.Internal.NpgsqlConnector.<Open>g__OpenCore|195_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
   at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.ConnectorPool.<Get>g__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlConnection.<Open>g__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(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.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<>c__DisplayClass33_0`2.<<ExecuteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func`4 operation, Func`4 verifySucceeded, TState state, CancellationToken cancellationToken)" (43386701)
System.TimeoutException: The operation has timed out.
   at Npgsql.Util.NpgsqlTimeout.Check()
   at Npgsql.Util.NpgsqlTimeout.CheckAndGetTimeLeft()
   at Npgsql.Util.NpgsqlTimeout.CheckAndApply(NpgsqlConnector connector)
   at Npgsql.Internal.NpgsqlConnector.<Open>g__OpenCore|195_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
   at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.ConnectorPool.<Get>g__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlConnection.<Open>g__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(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.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.<>c__DisplayClass33_0`2.<<ExecuteAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---

But the following attempts to do the same is succeeded and the pool always created with 4 connections

and one more things is that hence created connections gets closed automatically after a while, if i try to call an api which requires some data from the database, the first attempt to execute the query is always fails, and it always succeeds in the second attempt


builder.Services.AddDbContext<DbContextClass>(options =>
{
    options.UseNpgsql(connectionString,
        options =>
        {
            options.CommandTimeout(15);
            options.EnableRetryOnFailure(2);
        }
        );
});

this is my retry strategy.

any help is appreciated

9
  • 1
    I have manually closed all connections using connections.ForEach(connection => { connection.Close(); }); @MitchWheat Commented Jan 11, 2024 at 12:21
  • 1
    This code isn't initializing any kind of pool, it's leaking connections. The size of the pool is controlled by ADO.NET and NpgSQL through connection string settings. The error may be caused due to network or server issues. If you connect to a shared database, host or a cloud database, there's no guarantee that the database will be up when your site starts Commented Jan 11, 2024 at 12:24
  • 1
    have manually closed should one of those operations fail, all the other connections will remain open. What happens if you remove that code and the hard-coded timeout in UseNpgsql? What's the actual connection string? What happens if you increase the default connection timeout? Commented Jan 11, 2024 at 12:27
  • 1
    Host=localhost;Database=mydb;Username=postgres;Password=password;Timeout=15;Connection Idle Lifetime=86400;Connection Pruning Interval=86400;Keepalive=5;Minimum Pool Size=10; this is my connection string. I thought the above code will open some connections and upon closing it Npgsql will keep them in its Pool, I have inspected its Npgsql.PoolManager and i was able to see 4 Npgsql.Connectors initialised inside it @PanagiotisKanavos Commented Jan 11, 2024 at 12:30
  • 3
    Since I am using AWS RDS, i am not sure whether it becomes idle after some time. I did not find anything about idle state in the docs. Intially my problem was with the APIs getting delayed more than 15 seconds at random. When i logged the connections in the pool i was able to find that the connection pool is empty when the API delay happens. So inorder to fix that at the application startup i try to create 5 connections, so that the connections will be available in the pool. I cannot increase the connection timeout. Is there any way to keep the connections alive? @PanagiotisKanavos Commented Jan 11, 2024 at 12:56

1 Answer 1

0

I faced the same issue where the first connection attempt or a connection after a longer period would immediately time out. From my observations, the first connection attempt always takes significantly more time. Increasing the timeout, pool size and pooling in the connection string helped in my case. I added these parameters: Timeout=60;Command Timeout=60;Pooling=true;MinPoolSize=1;MaxPoolSize=200

Sign up to request clarification or add additional context in comments.

2 Comments

That was mentioned in the comments a year ago. This doesn't need some kind of observation, it's well documented 1) When you buy a managed database and pay only for usage time, the database shuts down after some time of inactivity. You pay to keep the database up for longer or for faster startup. Usually this means paying for a higher tier 2) With cloud services, the machine and hence the IP where the database runs changes from one execution to the next. The same DNS name has to be resolved to a new IP. The DNS lookup timeout is 15s.
The actual database version matters too. Newer drivers handle unreliable cloud connections better than older ones.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.