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

为何C#中DoWithRetry的try/catch无法捕获Kusto限流异常?

问题描述

我尝试在C#中用一个可复用的try/catch重试逻辑执行Kusto查询,代码如下:

public static T DoWithRetry<T>(Func<T> func, TimeSpan sleepPeriod, int tryCount = 3)
{
    if (tryCount <= 0)
        throw new ArgumentOutOfRangeException(nameof(tryCount));

    while(true)
    {
        try
        {
            return func();
        }
        catch (Exception ex)
        {
            if (--tryCount == 0)
                throw;
            Console.WriteLine($"Encountered exception {ex.Message}");
            Console.WriteLine($"Retrying in {sleepPeriod}...");
            Thread.Sleep(sleepPeriod);
        }
    }            
}

调用方式:

try 
{
    var res = DoWithRetry(() =>
    {
       return kustoClient.ExecuteQuery($"KustoQuery");
    }, TimeSpan.FromMinutes(3));
}
catch (Exception ex)
{
    Console.Error.WriteLine($"Exception Message: {ex.Message}");
    return "failed, please check.";
}

但遇到Kusto抛出限流异常时,该异常从未被DoWithRetry内部的try/catch捕获,反而被外层try/catch捕获。如果在lambda中手动抛出异常:

var res = DoWithRetry(() =>
{
   throw new KustoRequestThrottledException();
}, TimeSpan.FromMinutes(3));

异常却能被DoWithRetry内部的try/catch捕获。请问是什么原因导致Kusto的异常无法被内部捕获?


问题原因与解决方法

核心原因

Kusto客户端的ExecuteQuery方法返回的是延迟执行的结果集(比如IEnumerable或类似惰性枚举类型)。当你在lambda中return kustoClient.ExecuteQuery(...)时,查询并没有立即执行,只是返回了一个代表查询结果的待枚举对象。真正的查询执行发生在你外层代码使用这个结果(例如遍历、转换结果)的时候,此时已经脱离了DoWithRetry内部的try/catch块,所以异常会被外层的try/catch捕获。

而手动抛出异常是在lambda执行时立即触发的,因此会被DoWithRetry的内部try/catch直接捕获,进入重试逻辑。

解决方案

1. 强制立即执行查询(同步场景)

在lambda内部将延迟执行的结果转为立即执行的集合,比如用ToList()或ToArray(),确保查询在DoWithRetry的try/catch范围内执行:

var res = DoWithRetry(() =>
{
   // 用ToList()强制枚举结果,触发查询执行
   return kustoClient.ExecuteQuery($"KustoQuery").ToList();
}, TimeSpan.FromMinutes(3));

2. 使用异步重试逻辑(推荐)

如果Kusto客户端提供了异步版本的ExecuteQueryAsync方法,建议使用异步重试逻辑,避免阻塞线程,同时确保异常在异步调用时被正确捕获:

// 异步重试方法
public static async Task<T> DoWithRetryAsync<T>(Func<Task<T>> func, TimeSpan sleepPeriod, int tryCount = 3)
{
    if (tryCount <= 0)
        throw new ArgumentOutOfRangeException(nameof(tryCount));

    while (true)
    {
        try
        {
            return await func();
        }
        catch (Exception ex)
        {
            if (--tryCount == 0)
                throw;
            Console.WriteLine($"Encountered exception {ex.Message}");
            Console.WriteLine($"Retrying in {sleepPeriod}...");
            await Task.Delay(sleepPeriod);
        }
    }
}

调用示例:

try 
{
    var res = await DoWithRetryAsync(async () =>
    {
       // 异步执行查询并等待结果
       return await kustoClient.ExecuteQueryAsync($"KustoQuery");
    }, TimeSpan.FromMinutes(3));
}
catch (Exception ex)
{
    Console.Error.WriteLine($"Exception Message: {ex.Message}");
    return "failed, please check.";
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:01:19