WaitAndRetry 策略中包含的 Polly 超时策略不起作用

问题描述 投票:0回答:1

我有一项服务,可以使用

FileStream,
通过某些网络写入文件,而不会出现写入超时。我添加了一个 Polly
WaitAndRetry
策略来处理偶尔的写入失败,效果很好。我注意到有时写入会挂起,所以我尝试将超时策略包装在重试策略中,以限制每次写入尝试。

public class Retrier
{
    private readonly CancellationToken _cancellationToken;

    public Retrier(CancellationToken cancellationToken)
    {
        _cancellationToken = cancellationToken;
    }

    public void Start(IService service)
    {
        var retryPolicy = Policy
            .Handle<IOException>()
            .WaitAndRetry(
                retryCount: 3,
                sleepDurationProvider: (retries) => TimeSpan.FromSeconds(retries * 10));
        var timeoutPolicy = Policy.Timeout(seconds: 60);
        var combinedPolicy = retryPolicy.Wrap(timeoutPolicy);
        var result = combinedPolicy.ExecuteAndCapture(
            (ct) => 
            {
                service.Write(ct);
            },
            _cancellationToken);

        // Do some other stuff
    }
}

但是,使用包装策略时,根本不会调用写入操作,例如输入

ExecuteAndCapture
并调用操作,但执行只是继续在下面“执行其他操作”。一个简单的测试方法验证
Write
被调用了零次。

[TestMethod]
public void Retrier_Start_When_IOExceptionOnce_CallsExecuteTwice()
{
    var attempt = 0;
    var mock = new Mock<IService>();

    mock
        .Setup(svc => svc.Write(_cancellationTokenSource.Token))
        .Returns(() =>
        {
            attempt++; 

            if (attempt == 1)
            {
                throw new IOException("Failed");
            }

            return 1;
        })
        .Verifiable();

    _testee.Start(mock.Object);
    mock.Verify(svc => svc.Write(_cancellationTokenSource.Token), Times.Exactly(2));
}

Write 是一项简单的服务,没有魔法:

public int Write(CancellationToken cancellationToken)
{
    cancellationToken.ThrowIfCancellationRequested();

    var tempFullPath = ...

    using (var fw = new FileStream(tempFullPath, FileMode.Create, FileAccess.Write))
    {
        fw.Write(_buffer, 0, _buffer.Length);
    }

    File.Move(tempFullPath, _finalFullPath);

    return ++Count;
}

我浏览了类似的问题,但找不到解决方案。 我做错了什么?

c# timeout cancellation polly retry-logic
1个回答
1
投票

如果超时策略生效,则会抛出一个

TimeoutRejectedException

因此,您还需要修改重试来处理该异常。

var timeoutPolicy = Policy.Timeout(seconds: 60);
var retryPolicy = Policy
            .Handle<IOException>()
            .Or<TimeoutRejectedException>()
            .WaitAndRetry(
                retryCount: 3,
                sleepDurationProvider: (retries) => TimeSpan.FromSeconds(retries * 10));

var combinedPolicy = Policy.Wrap(retryPolicy, timeoutPolicy);

更新#1

这是一个带有工作示例的 dotnet fiddle 链接: http://dotnetfiddle.net/uTvCJA

© www.soinside.com 2019 - 2024. All rights reserved.