zoukankan      html  css  js  c++  java
  • 使用 EF Core 的 EnableRetryOnFailure 解决短暂的数据库连接失败问题

    阿里云服务器有时会出现短暂的连接不上数据库服务器(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 });
            });
    });
  • 相关阅读:
    优秀案例:18个美丽的图片在网页设计中的使用
    推荐几款很棒的 JavaScript 表单美化和验证插件
    25套用于 Web UI 设计的免费 PSD 网页元素模板
    字体排布艺术:30例可圈可点的版式设计欣赏
    Twitter Bootstrap 3.0 正式发布,更好地支持移动端开发
    引领网页设计潮流的优秀网页作品赏析《第三季》
    Codrops 优秀教程:实现效果精美的多层推拉菜单
    字体大宝库:设计师必备的精美免费英文字体
    优秀前端开发教程:超炫的 Mobile App 3D 演示
    推荐35个新鲜出炉的响应式 Web 设计实例
  • 原文地址:https://www.cnblogs.com/dudu/p/8433013.html
Copyright © 2011-2022 走看看