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

如何用SqlRetryLogicBaseProvider处理Azure SQL伸缩时的连接重试

Azure SQL伸缩时重试逻辑不触发的问题解决

错误号0无法触发重试的原因

错误号0并非SQL Server返回的原生瞬态错误码,而是Microsoft.Data.SqlClient客户端在无法获取服务器明确错误响应时使用的占位符。这类错误通常属于非瞬态场景(比如连接彻底中断且无服务器反馈),即便手动添加到TransientErrors列表,重试逻辑也不会触发——客户端内部会先对错误的“可重试性”做基础判定,0不在默认的可重试错误分类中,手动添加无法覆盖这一判定。

Azure SQL伸缩会话Kill错误未触发重试的核心问题

你遇到的「Cannot continue the execution because the session is in the kill state」错误,对应的实际SQL错误码可能并非你预期的0,建议在catch块中打印SqlException.Number确认真实错误码:

catch (Exception ex)
{
    if (ex is SqlException sqlEx)
    {
        Console.WriteLine($"ERROR CODE: {sqlEx.Number}, MESSAGE: {sqlEx.Message}");
    }
    else
    {
        Console.WriteLine($"ERROR: {ex.Message}");
    }
}

此外,你的代码存在以下几个影响重试逻辑的问题:

  1. 重复设置重试提供器:同时给SqlConnection和SqlCommand绑定了RetryLogicProvider,可能导致内部逻辑冲突,建议只给SqlCommand设置(或只给连接设置,二选一)。
  2. 静态连接的状态混乱:使用静态SqlConnection,重试时手动关闭再打开连接,容易导致连接状态不一致,建议改用局部连接对象。
  3. 重试事件的强制转换风险:将SqlRetryingEventArgs的s参数强制转为SqlCommand,若触发重试的是连接对象,会抛出空引用异常,直接终止重试流程。

修正后的代码示例

internal class Program
{
    private const string CnnStringFormat = "Data Source = localhost; Initial Catalog = dbtest; User ID = sa; Password=aaaaaa;Encrypt=True;TrustServerCertificate=True";

    static void Main(string[] args)
    {
        var options = new SqlRetryLogicOption()
        {
            NumberOfTries = 5,
            MaxTimeInterval = TimeSpan.FromSeconds(60),
            DeltaTime = TimeSpan.FromSeconds(15),
            // 保留经确认的瞬态错误码,移除无效的0
            TransientErrors = new List<int> { -1, -2, 109, 233, 997, 1222, 10060, -2146232060, 596 }
        };

        var provider = SqlConfigurableRetryFactory.CreateExponentialRetryProvider(options);
        
        provider.Retrying += (object sender, SqlRetryingEventArgs e) =>
        {
            NotificaRetry(e);
            // 无需手动关闭/打开连接,重试逻辑会自动处理连接重建
        };

        SqlDataReader leitor = null;
        try
        {
            // 使用局部连接,避免静态对象的状态问题
            using (var connection = new SqlConnection(CnnStringFormat))
            {
                connection.Open();
                using (var comando = new SqlCommand("spGetLoadTest", connection) 
                { 
                    CommandType = System.Data.CommandType.StoredProcedure,
                    CommandTimeout = 300,
                    RetryLogicProvider = provider // 仅给命令设置重试提供器
                })
                {
                    leitor = comando.ExecuteReader();
                    var count = leitor.Depth;
                    var colunas = leitor.FieldCount;
                }
            }
        }
        catch (Exception ex)
        {
            if (ex is SqlException sqlEx)
            {
                Console.WriteLine($"ERROR CODE: {sqlEx.Number}, MESSAGE: {sqlEx.Message}");
            }
            else
            {
                Console.WriteLine($"ERROR: {ex.Message}");
            }
        }
        finally
        {
            leitor?.Close();
        }
    }

    private static void NotificaRetry(SqlRetryingEventArgs e)
    {
        int attempts = e.RetryCount + 1;
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine($"attempt {attempts} - current delay time:{e.Delay}");
        Console.WriteLine($"error: {e.Exceptions[e.RetryCount].Message}"); // 修正索引,避免第一次重试时索引越界
        Console.ForegroundColor = ConsoleColor.DarkGray;
    }
}

关键说明

  1. 移除错误号0:由于0是客户端占位符,无法触发重试,直接从TransientErrors中移除。
  2. 局部连接+using语句:确保连接自动释放,避免状态混乱,重试时会自动重建连接。
  3. 仅给命令设置重试提供器:避免连接和命令的重试逻辑冲突,让命令层面的重试处理执行过程中的错误。
  4. 修正重试事件的异常索引:原代码中e.Exceptions[e.RetryCount-1]会在第一次重试时出现索引越界,改为e.Exceptions[e.RetryCount]即可正确获取当前重试对应的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 01:30:55