简体   繁体   English

记录异常并重新抛出的 Polly 策略

[英]Polly policy to log exception and rethrow

I consider to use Polly to create policy to log exception and rethrow.我考虑使用Polly创建策略来记录异常并重新抛出。 I didn't find an existing method that allow it out of the box, but some options that I see are我没有找到允许开箱即用的现有方法,但我看到的一些选项是

Fallback倒退

// Specify a substitute value or func, calling an action (e.g. for logging)
// if the fallback is invoked.
Policy.Handle<Whatever>()
.Fallback<UserAvatar>(UserAvatar.Blank,
    onFallback: (exception, context) =>
    {
        _logger.Log(exception, context);
        throw exception;
    });

Question: is it ok to throw exception from Fallback?问题:可以从 Fallback 中抛出异常吗?

Timeout暂停

Policy.Timeout(1, T30meoutStrategy.Pessimistic,
(context, timespan, task) =>
{
    // ContinueWith important!: the abandoned task may very well still be executing,
    // when the caller times out on waiting for it!
    task.ContinueWith(t =>
    {
        if (t.IsFaulted)
        {
            logger.Error(context,t.Exception);
            throw exception;
        }
    });
}

Or Retry重试

Policy.Handle<DivideByZeroException>().Retry(0,
(exception, retryCount) =>
{
    logger.Error(context,exception);
    throw exception;
});

Question: is 0 retries supported?问题:是否支持0次重试?

Or KISS and write simple try/catch with throw by myself.或者 KISS 并自己编写简单的 try/catch with throw。

Which of these methods is better?这些方法哪种更好? What are your recommendation?你有什么建议?

If you do not already have Polly in the mix, try/catch would seem simplest.如果您还没有 Polly,那么 try/catch 似乎是最简单的。

If you already have Polly in the mix, FallbackPolicy can safely be re-purposed in the way you suggest.如果您已经有 Polly,则可以按照您建议的方式安全地重新调整FallbackPolicy的用途。 The onFallback delegate and fallback action or value are not governed by the .Handle<>() clauses of the Policy , so you can safely rethrow an exception from within the onFallback delegate. onFallback委托和回退操作或值不受.Handle<>()子句控制,因此您可以安全地从onFallback委托中重新抛出异常。

Policy<UserAvatar>.Handle<Whatever>()
.Fallback<UserAvatar>(UserAvatar.Blank,
    onFallback: (exception, context) =>
    {
        _logger.Log(exception, context);
        throw exception;
    });

The approach your question outlines with TimeoutPolicy would only capture exceptions thrown by delegates the caller had earlier walked away from due to timeout, and only in TimeoutMode.Pessimistic ;您的问题使用TimeoutPolicy概述的方法只会捕获调用者先前因超时而离开的委托引发的异常,并且仅在TimeoutMode.Pessimistic not all exceptions.并非所有例外。


The approach your question outlines with .Retry(0, ...) would not work.您的问题概述的方法.Retry(0, ...)不起作用。 If no retries are specified, the onRetry delegate would not be invoked.如果未指定重试,则不会调用onRetry委托。


To avoid the untidiness of repurposing FallbackPolicy , you could also code your own LogThenRethrowPolicy , within Polly's structures.为了避免重新利用FallbackPolicy的不整洁,您还可以在 Polly 的结构中编写自己的LogThenRethrowPolicy This commit (which added the simple NoOpPolicy ) exemplifies the minimum necessary to add a new policy. 此提交(添加了简单的NoOpPolicy )举例说明了添加新策略所需的最低限度。 You could add an implementation similar to NoOpPolicy but just try { } catch { /* log; rethrow */ }您可以添加类似于NoOpPolicy的实现,但只需try { } catch { /* log; rethrow */ } try { } catch { /* log; rethrow */ }


EDIT January 2019 : Polly.Contrib now also contains a Polly.Contrib.LoggingPolicy which can help with this.编辑 2019 年 1 月:Polly.Contrib 现在还包含一个Polly.Contrib.LoggingPolicy可以帮助解决这个问题。

https://github.com/App-vNext/Polly-Samples/blob/master/PollyDemos/Async/AsyncDemo02_WaitAndRetryNTimes.cs shows that you can use the onRetry: option, at least for WaitAndRetryAsync. https://github.com/App-vNext/Polly-Samples/blob/master/PollyDemos/Async/AsyncDemo02_WaitAndRetryNTimes.cs显示您可以使用onRetry:选项,至少对于 WaitAndRetryAsync。 I haven't looked at the others yet.其他的我还没看。

HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3,
    retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))  // exponential back-off: 2, 4, 8 etc
                    + TimeSpan.FromMilliseconds(Jitterer.Next(0, 1000)), // plus some jitter: up to 1 second
    onRetry: (response, calculatedWaitDuration) =>
    {
        logger.LogError($"Failed attempt. Waited for {calculatedWaitDuration}. Retrying. {response.Exception.Message} - {response.Exception.StackTrace}");
    }
);

Here my solution with generic method这是我的通用方法解决方案

public async Task<T> PollyRetry<T>(
        Func<Task<T>> action)
    {

        bool hasFallback = false;
        Exception ex = null;

        var fallbackPolicy = Policy<T>.Handle<Exception>().FallbackAsync(
            default(T), d =>
            {
                //log final exception

                ex = d.Exception;

                hasFallback = true;
                return Task.FromResult(new { });

            });

        var retryPolicy = Policy
            .Handle<Exception>()
            .WaitAndRetryAsync(3,
                retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                (res, timeSpan, context) =>
                {
                    //log exception
                });

        var policyResult = await fallbackPolicy.WrapAsync(retryPolicy).ExecuteAndCaptureAsync(action);

        if (hasFallback && ex != null)
            throw ex;

        return policyResult.Result;
    }

//call service with retry logic
        TestResponse response = await _pollyRetryService.PollyRetry(async () =>
        {
            return await _testService.Test(input);

        });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM