使用 EF Core 的 EnableRetryOnFailure 解决短暂的数据库连接失败问题

本文介绍了如何使用EF Core的EnableRetryOnFailure方法来处理阿里云服务器与RDS间短暂的连接失败问题。当遇到SQL Server连接异常时,通过Startup配置重试机制并未达到预期效果。经过分析,发现需要指定特定的errorNumbersToAdd,最终成功解决异常并实现重试功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阿里云服务器有时会出现短暂的连接不上数据库服务器(RDS)的问题,之前由于没有启用 Entity Framework Core 的失败重试功能(默认是禁用的),短暂的连接失败立马会引发下面的异常从而出现500错误。

System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 40 - Could not open a connection to SQL Server)

为了解决这个问题,在 Startup 中添加如下的代码启用 RetryOnFailure 。

services.AddDbContext<CnblogsDbContext>(options =>
{
    options.UseSqlServer(Configuration.GetConnectionString("cnblogs"),
        builder =>
        {
            builder.EnableRetryOnFailure(
                maxRetryCount: 5,
                maxRetryDelay: TimeSpan.FromSeconds(30),
                errorNumbersToAdd: null);
        });
});

但是测试发现不起作用。

期望的测试结果是这样的:启动 asp.net core 站点 ->  curl 发请求 -> 正常响应 -> 停止 SQL Server 服务器 -> curl 发请求 -> 等待 -> 30秒之后启动 SQL Server -> 正常响应。

实际的测试结果却是这样:启动 asp.net core 站点 ->  curl 发请求 -> 正常响应 -> 停止 SQL Server 服务器 -> curl 发请求 -> 15秒左右出现500错误,报上面的异常。

难道这个异常不在 RetryOnFailure 的默认范围?

于是通过 errorNumbersToAdd 添加 0x80131904 错误码:

var errorNumer = 0x80131904;
builder.EnableRetryOnFailure(
    maxRetryCount: 5,
    maxRetryDelay: TimeSpan.FromSeconds(30),
    errorNumbersToAdd: new int[] { (int)errorNumer });

却依然不起作用。

别无他法,只能硬啃 EFCore 的源代码找线索了,于是找到 SqlServerTransientExceptionDetector

public class SqlServerTransientExceptionDetector
{
    public static bool ShouldRetryOn([NotNull] Exception ex)
    {
        if (ex is SqlException sqlException)
        {
            foreach (SqlError err in sqlException.Errors)
            {
                switch (err.Number)
                {
                    case 49920:
                    case 49919:
                    case 49918:
                    case 41839:
                    case 41325:
                    case 41305:
                    case 41302:
                    case 41301:
                    case 40613:
                    case 40501:
                    case 40197:
                    case 10929:
                    case 10928:
                    case 64:
                    case 20:
                }
            }

            return false;
        }

        if (ex is TimeoutException)
        {
            return true;
        }

        return false;
    }
}

原来是根据 SqlError.Number 来判断的, 上面的数字都这么小,看来 0x80131904 不是 SqlError.Number ,再次查看错误日志发现在 System.Data.SqlClient.SqlException (0x80131904) 之前有下面一行日志:

Error Number:2,State:0,Class:20

原来是 2 ,于是在 errorNumbersToAdd  中添加这个 error number ,问题就解决了。

services.AddDbContext<CnblogsDbContext>(options =>
{
    options.UseSqlServer(Configuration.GetConnectionString("cnblogs"),
        builder =>
        {
            builder.EnableRetryOnFailure(
                maxRetryCount: 5,
                maxRetryDelay: TimeSpan.FromSeconds(30),
                errorNumbersToAdd: new int[] { 2 });
        });
});

转载于:https://www.cnblogs.com/dudu/p/8433013.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值