.NET 8 新的 API 錯誤自動重試 套件

Microsoft.Extensions.Http.Resilience 套件 是微軟新推出的套件(使用到 Polly),使我們能夠更穩定的呼叫 API ,在遇到網路問題或服務錯誤時能夠適當的重試。版本號從 8.0.0 開始,可以使用以下指令安裝:
	
dotnet add package Microsoft.Extensions.Http.Resilience
    

下面是一個完整的 API 呼叫重試示範
    
var httpClient = new HttpClient();

var pipeline = new ResiliencePipelineBuilder()
    .AddRetry(new RetryStrategyOptions()
    {
        MaxRetryAttempts = 3, // 最大重試次數(共 4 次)
        Delay = TimeSpan.FromSeconds(3), // 每次重試延遲
        BackoffType = DelayBackoffType.Constant, // 每次重試的延遲方式(每次相同延遲
        UseJitter = true, // 抖動(隨機延遲)
        
        ShouldHandle = new PredicateBuilder()
            .Handle<HttpRequestException>(), // 要處理的例外

        OnRetry = retryArguments => // 重試時的處理
        {
            Console.WriteLine($"Retry {retryArguments.AttemptNumber} times");
            Console.WriteLine($"Exception: {retryArguments.Outcome.Exception}");
            return ValueTask.CompletedTask;
        },
    })
    .AddTimeout(TimeSpan.FromSeconds(30)) // API 超時時間
    .Build();

var response = await pipeline.ExecuteAsync(async cancellationToken =>
    {
    
        return await httpClient.GetAsync(url, cancellationToken); // 發起 API 請求
    }
);

var content = await response.Content.ReadAsStringAsync();
    

上面的用法不算太難,但是有點冗長。如果使用 ASP.NET Core 的話可以在 Program.cs 中註冊就好了:
    
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResiliencePipeline("default", pipeline => // 重試策略名稱
{
    pipeline
        .AddRetry(new RetryStrategyOptions()
        {
            MaxRetryAttempts = 3, // 最大重試次數(共 4 次)
            Delay = TimeSpan.FromSeconds(3), // 每次重試延遲
            BackoffType = DelayBackoffType.Constant, // 每次重試的延遲方式(每次相同延遲
            UseJitter = true, // 抖動(隨機延遲)

            ShouldHandle = new PredicateBuilder()
                .Handle<HttpRequestException>(), // 要處理的例外

            OnRetry = retryArguments => // 重試時的處理
            {
                Console.WriteLine($"Retry {retryArguments.AttemptNumber} times");
                Console.WriteLine($"Exception: {retryArguments.Outcome.Exception}");
                return ValueTask.CompletedTask;
            },
        })
        .AddTimeout(TimeSpan.FromSeconds(30)); // API 超時時間
});

var app = builder.Build();

    

這裡偷懶一點,直接在 Controller 中使用:
    
[ApiController]
[Route("[controller]")]
public class TestController(ResiliencePipelineProvider<string> pipelineProvider) : ControllerBase
{
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        string url = "http://localhost:3000/users";
        
        var httpClient = new HttpClient();

        var pipeline = pipelineProvider.GetPipeline("default"); // 重試策略名稱
        
        var response = await pipeline.ExecuteAsync(async cancellationToken =>
            {
                return await httpClient.GetAsync(url, cancellationToken); // 發起 API 請求
            }
        );

        if (response.StatusCode != HttpStatusCode.OK)
            return StatusCode((int)response.StatusCode, response.ReasonPhrase);

        var content = await response.Content.ReadAsStringAsync();
        return Ok(content);
    }
    


註: 在 ASP.NET Core 中可以使用 IHttpClientFactory 來代替直接實例化 HttpClient

參考資料:
Microsoft.Learn - Build resilient HTTP apps: Key development patterns

留言

張貼留言

如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com