首页 > 解决方案 > 如何使用 polly 启用超时策略

问题描述

我正在尝试使用 polly 的超时策略。

    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        timeoutPolicy().GetAwaiter().GetResult();

        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
        Console.ReadKey();
    }

    static async Task timeoutPolicy()
    {
        AsyncTimeoutPolicy<HttpResponseMessage> timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(1); // setup the timeout limit to be 1 sec

        HttpResponseMessage response = await timeoutPolicy.ExecuteAsync((ct) => LongOperation(), CancellationToken.None);

    }

    static Task<HttpResponseMessage> LongOperation()
    {
        return Task<HttpResponseMessage>.Factory.StartNew(() =>
        {
            Thread.Sleep(5000); // Sleep 5 seconds
            return new HttpResponseMessage()
            {
                StatusCode = HttpStatusCode.BadRequest
            };

        });
    }

我希望在 1 秒后抛出异常,因为这是我设置的超时上限。但目前不会抛出异常,LongOperation() 方法会在大约 5 秒后正常返回。

为什么超时策略在这种情况下不起作用?

标签: c#polly

解决方案


为什么超时策略在这种情况下不起作用?

PollyTimeoutPolicy有两种模式:

乐观模式是默认模式,因此您发布的代码使用此模式。但 (a)LongOperation()在贴出的代码中不响应合作取消;所以策略不会超时。

带有异步策略的悲观模式被有意设计为仅用于管理符合正常异步模式的委托Thread.Sleep()在张贴LongOperation()中是完全同步的;因此,您的示例也不会仅通过切换到TimeoutStrategy.Pessimistic.


TimeoutStrategy.Optimistic是呼叫通过的最佳模拟HttpClient,因为那些呼叫确实响应CancellationToken

await Task.Delay(...)可以通过尊重 a来模拟异步超时策略的乐观模式超时操作CancellationToken如下所示

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Polly;
using Polly.Timeout;

public class Program
{ 
    public static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        try {
            timeoutPolicy().GetAwaiter().GetResult();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
    }

    static async Task timeoutPolicy()
    {
        var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(1); // setup the timeout limit to be 1 sec

        HttpResponseMessage response = await timeoutPolicy.ExecuteAsync((ct) => LongOperation(ct), CancellationToken.None);
    }

    static async Task<HttpResponseMessage> LongOperation(CancellationToken token)
    {
        await Task.Delay(5000, token);
        return new HttpResponseMessage()
        {
            StatusCode = HttpStatusCode.BadRequest
        };
    }
} 

推荐阅读