在Polly策略回退中组合Polly策略和访问处理异常



给定以下f#片段

//User Code
.. code that can throw exceptions
"Success"

P1政策
Policy
.Handle<CosmosException>(fun cx -> cx.StatusCode = HttpStatusCode.TooManyRequests)
.WaitAndRetryForever((fun _ cx _ -> (cx :?> CosmosException).RetryAfter.Value), (fun _ _ _ _ -> ()))

P2政策
Policy<string>
.Handle<Exception>()
.Fallback("Failure")

P3政策
Policy<string>
.Handle<Exception>()
.Fallback(fun ex -> ex.Message)

问题1 -如何结合P1和P2?

将P1和P2组合在策略p中,使:

  • 如果用户代码成功,则"成功";返回给调用者
  • 如果用户代码抛出CosmosException, P使用返回的RetryAfter时间跨度永远重试
  • 如果用户代码抛出任何其他异常,则"失败";返回给调用者

问题# 2 -如何写P3?

在构造回退返回值 时,似乎没有允许访问处理过的异常来使用它的回退重载。Final作用域是组合P1和P3来获得一个策略PFinal,使得:

  • 如果用户代码成功,则"成功";返回给调用者
  • 如果用户代码抛出CosmosException, PFinal使用返回的RetryAfter时间span永远重试
  • 如果用户代码抛出任何其他异常,则将处理过的异常消息返回给调用者

问题1的答案

为了能够链接策略,您需要将它们定义为兼容策略。你的p2返回一个string,而你的p1什么也不返回。因此,您需要更改p1以返回string。然后你可以使用Policy.Wrap来定义链接,升级。

我不是一个f#开发人员,所以我将在c#中提出解决方案。但是在两种语言中是一样的:

var p1 = Policy<string>
.Handle<CosmosException>(ex => ex.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryForever(sleepDurationProvider: (_, dr, __) => ((CosmosException)dr.Exception).RetryAfter.Value,
onRetry: (_, __, ___) => { });
var p2 = Policy<string>
.Handle<Exception>()
.Fallback("Failure");
var p = Policy.Wrap(p1, p2);
  • 请注意,我们必须在p1
  • 中将Policy更改为Policy<string>
  • 还要注意sleepDurationProvider不会接收Exception作为参数
    • 相反,它将收到一个DelegateResult<string>,它有两个互斥的属性:ExceptionResult

问题2的答案

  • fallbackAction委托接收DelegateResult<string>作为参数
var p2 = Policy<string>
.Handle<Exception>()
.Fallback(fallbackAction: (dr, _, __) => dr.Exception.Message,
onFallback: (_, __) => { });

Update # 1:提供清晰度

p1定义从Policy更改为Policy<string>还有另一个含义:您要装饰的代码应该返回一个字符串(即"Success")

修改前:

//user code
//to be decorated code which might throw exception
return "Success";

修改后:

//user code
//The decorated code either return "Success" or throws CosmosException 
return combinedPolicy.Execute(...

更新# 2修复排序

我建议链接p1p2Policy.Wrap。很不幸,我给你看错了订单Policy.Wrap(p1, p2)正确的Policy.Wrap(p2, p1),因为最右边的参数是最内部的,最左边的参数是最外部的。所以,在你的例子中,重试是内部的,而回退是外部的。

给您带来的不便我深表歉意。

最新更新