You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET6应用中Npgsql随机连接超时问题求助

问题场景

基于PostgreSQL + Npgsql的.NET 6应用中,手动初始化连接池时遇到以下问题:

  • 首次创建连接总是超时,最终仅成功创建4个连接
  • 连接池中的连接闲置一段时间后自动关闭,此时首次调用数据库API失败,第二次请求恢复正常

手动初始化连接池代码

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

for (int i = 0; i < 5; i++)
{
    NpgsqlConnection connection = new NpgsqlConnection(connectionString);
    try
    {
        connection.Open(); // 实际打开连接
    }
    catch (Exception e)
    {
        continue;
    }
    connections.Add(connection);
}
connections.ForEach(connection => { connection.Close(); });

超时错误日志

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 ---

当前重试策略配置

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

1. 移除手动连接池初始化代码

Npgsql自带内置连接池,无需手动创建和管理连接。手动创建连接再关闭的操作不仅多余,还会干扰内置连接池的正常逻辑,导致首次连接超时。

内置连接池默认会自动管理连接的创建、复用和销毁,只需通过连接字符串配置池参数即可,示例:

Host=myhost;Database=mydb;Username=myuser;Password=mypass;Maximum Pool Size=5;Minimum Pool Size=5;Connection Idle Lifetime=300;
  • Maximum Pool Size:连接池最大连接数(默认100)
  • Minimum Pool Size:连接池保持的最小空闲连接数(默认0,设置为5可避免闲置后连接被释放)
  • Connection Idle Lifetime:连接闲置多久后被销毁(默认300秒,可根据需求调整)

2. 调整超时与重试策略

(1)增加连接超时时间

当前CommandTimeout=15是命令执行超时,而非连接建立超时。需在连接字符串中添加Timeout=30(单位秒),延长连接建立的超时时间:

Host=myhost;Database=mydb;Username=myuser;Password=mypass;Timeout=30;Maximum Pool Size=5;Minimum Pool Size=5;

(2)优化EF Core重试策略

EnableRetryOnFailure(2)默认只重试部分 transient 错误,需明确指定包含连接超时相关错误,确保首次连接超时能被自动重试:

builder.Services.AddDbContext<DbContextClass>(options =>
{
    options.UseNpgsql(connectionString,
        npgsqlOpts =>
        {
            npgsqlOpts.CommandTimeout(15);
            npgsqlOpts.EnableRetryOnFailure(
                maxRetryCount: 2,
                maxRetryDelay: TimeSpan.FromSeconds(1),
                errorCodesToAdd: new[] { "57P01", "08006", "08001" } // 覆盖连接终止、连接失败等常见 transient 错误
            );
        });
    // 确保异步操作也能正确触发重试逻辑
    options.UseExecutionStrategy(context => new NpgsqlExecutionStrategy(context, 2, TimeSpan.FromSeconds(1)));
});

3. 验证连接池状态

可以通过Npgsql内置方法查看连接池状态,确认连接是否正常维护:

var poolStats = NpgsqlConnection.GetPoolStatistics(connectionString);
Console.WriteLine($"当前活跃连接数:{poolStats.ActiveConnections}");
Console.WriteLine($"当前空闲连接数:{poolStats.IdleConnections}");

内容的提问来源于stack exchange,提问作者Shah_jahan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:37:02