使用 Polly 重试
retry using Polly
这2个重试策略是否表示相同?
Policy
.Handle<SomeExceptionType>()
.WaitAndRetry(
new[]
{
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1)
});
Policy
.Handle<SomeExceptionType>()
.WaitAndRetry(
3,
retryAttempt => TimeSpan.FromMinutes(1)
);
是的,他们也这样做。
两个代码都定义了一个最多执行 4 次相同操作的策略:初始尝试 + 三次额外尝试。
两个重载的主要区别如下:
- 前者以static方式定义惩罚
- 它预定义了不同尝试之间的延迟
- 后者以动态方式定义惩罚
- 它可以根据即将发生的重试来计算延迟
在您的特定示例中,您的第二个替代方案可以这样定义:
Policy
.Handle<SomeExceptionType>()
.WaitAndRetry(
3,
_ => TimeSpan.FromMinutes(1)
);
使用丢弃运算符,您明确声明您没有在 sleepDurationProvider
中使用该参数来计算新的延迟。
为了清楚起见,我使用了 penalty、delay 和 sleep post.
中可互换的术语
更新 #1
这里有两个示例,您可以在其中利用动态惩罚计算。
指数退避 + 抖动
与其在每次尝试之间等待相同的时间,不如使用越来越大的延迟来为下游系统提供 space 自我修复。因此,例如:2、4、8 ...
jitter 只是一个小的随机数,以避免所有客户端同时尝试发送他们的重试尝试。所以它 scatters/disperse 客户端及时重试。
const int maxDelayInMilliseconds = 32 * 1000;
var jitterer = new Random();
Policy
.Handle<HttpRequestException>()
.WaitAndRetryForever(
retryAttempt =>
{
var calculatedDelayInMilliseconds = Math.Pow(2, retryAttempt) * 1000;
var jitterInMilliseconds = jitterer.Next(0, 1000);
var actualDelay = Math.Min(calculatedDelayInMilliseconds + jitterInMilliseconds, maxDelayInMilliseconds);
return TimeSpan.FromMilliseconds(actualDelay);
}
);
断路器感知重试
如果您使用断路器来避免在下游系统 self-healing 时淹没下游系统,您可以让您的重试意识到这一点。
默认情况下,所有策略都是独立的,并且彼此不知情。如果您在 CB 打开时发出重试尝试,那么您将收到 BrokenCircuitException
(因此它 short-cuts 执行)。但是您可以根据 CB 的状态动态计算延迟,这样您就可以跳过这些不必要的重试。
断路器定义
Policy<HttpResponseMessage>
.HandleResult(res => res.StatusCode == HttpStatusCode.InternalServerError)
.CircuitBreakerAsync(3, TimeSpan.FromSeconds(2),
onBreak: (dr, ts, ctx) => { ctx[SleepDurationKey] = ts; },
onReset: (ctx) => { ctx[SleepDurationKey] = null; });
重试定义
Policy<HttpResponseMessage>
.HandleResult(res => res.StatusCode == HttpStatusCode.InternalServerError)
.Or<BrokenCircuitException>()
.WaitAndRetryAsync(4,
sleepDurationProvider: (c, ctx) =>
{
if (ctx.ContainsKey(SleepDurationKey))
return (TimeSpan)ctx[SleepDurationKey];
return TimeSpan.FromMilliseconds(200);
});
详细描述了此高级用例。
这2个重试策略是否表示相同?
Policy
.Handle<SomeExceptionType>()
.WaitAndRetry(
new[]
{
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1)
});
Policy
.Handle<SomeExceptionType>()
.WaitAndRetry(
3,
retryAttempt => TimeSpan.FromMinutes(1)
);
是的,他们也这样做。
两个代码都定义了一个最多执行 4 次相同操作的策略:初始尝试 + 三次额外尝试。
两个重载的主要区别如下:
- 前者以static方式定义惩罚
- 它预定义了不同尝试之间的延迟
- 后者以动态方式定义惩罚
- 它可以根据即将发生的重试来计算延迟
在您的特定示例中,您的第二个替代方案可以这样定义:
Policy
.Handle<SomeExceptionType>()
.WaitAndRetry(
3,
_ => TimeSpan.FromMinutes(1)
);
使用丢弃运算符,您明确声明您没有在 sleepDurationProvider
中使用该参数来计算新的延迟。
为了清楚起见,我使用了 penalty、delay 和 sleep post.
中可互换的术语更新 #1
这里有两个示例,您可以在其中利用动态惩罚计算。
指数退避 + 抖动
与其在每次尝试之间等待相同的时间,不如使用越来越大的延迟来为下游系统提供 space 自我修复。因此,例如:2、4、8 ...
jitter 只是一个小的随机数,以避免所有客户端同时尝试发送他们的重试尝试。所以它 scatters/disperse 客户端及时重试。
const int maxDelayInMilliseconds = 32 * 1000;
var jitterer = new Random();
Policy
.Handle<HttpRequestException>()
.WaitAndRetryForever(
retryAttempt =>
{
var calculatedDelayInMilliseconds = Math.Pow(2, retryAttempt) * 1000;
var jitterInMilliseconds = jitterer.Next(0, 1000);
var actualDelay = Math.Min(calculatedDelayInMilliseconds + jitterInMilliseconds, maxDelayInMilliseconds);
return TimeSpan.FromMilliseconds(actualDelay);
}
);
断路器感知重试
如果您使用断路器来避免在下游系统 self-healing 时淹没下游系统,您可以让您的重试意识到这一点。
默认情况下,所有策略都是独立的,并且彼此不知情。如果您在 CB 打开时发出重试尝试,那么您将收到 BrokenCircuitException
(因此它 short-cuts 执行)。但是您可以根据 CB 的状态动态计算延迟,这样您就可以跳过这些不必要的重试。
断路器定义
Policy<HttpResponseMessage>
.HandleResult(res => res.StatusCode == HttpStatusCode.InternalServerError)
.CircuitBreakerAsync(3, TimeSpan.FromSeconds(2),
onBreak: (dr, ts, ctx) => { ctx[SleepDurationKey] = ts; },
onReset: (ctx) => { ctx[SleepDurationKey] = null; });
重试定义
Policy<HttpResponseMessage>
.HandleResult(res => res.StatusCode == HttpStatusCode.InternalServerError)
.Or<BrokenCircuitException>()
.WaitAndRetryAsync(4,
sleepDurationProvider: (c, ctx) =>
{
if (ctx.ContainsKey(SleepDurationKey))
return (TimeSpan)ctx[SleepDurationKey];
return TimeSpan.FromMilliseconds(200);
});
详细描述了此高级用例