[英]What is the best way to implement exponential retry in C# Azure Function 4.x with a Service Bus as a trigger?
[英]What is the best way to implement a Retry Wrapper in C#?
我们目前有一个天真的RetryWrapper,它会在发生异常时重试给定的func:
public T Repeat<T, TException>(Func<T> work, TimeSpan retryInterval, int maxExecutionCount = 3) where TException : Exception
{
...
对于retryInterval,我们在下一次尝试之前使用以下逻辑“等待”。
_stopwatch.Start();
while (_stopwatch.Elapsed <= retryInterval)
{
// do nothing but actuallky it does! lots of CPU usage specially if retryInterval is high
}
_stopwatch.Reset();
我不是特别喜欢这种逻辑,理想情况下我更希望重试逻辑不会发生在主线程上,你能想到更好的方法吗?
注意:我很高兴考虑.Net> = 3.5的答案
只要您的方法签名返回T,主线程就必须阻塞,直到完成所有重试。 但是,您可以通过让线程休眠而不是执行手动重置事件来减少CPU:
Thread.Sleep(retryInterval);
如果您愿意更改API,可以将其设置为不阻止主线程。 例如,您可以使用异步方法:
public async Task<T> RepeatAsync<T, TException>(Func<T> work, TimeSpan retryInterval, int maxExecutionCount = 3) where TException : Exception
{
for (var i = 0; i < maxExecutionCount; ++i)
{
try { return work(); }
catch (TException ex)
{
// allow the program to continue in this case
}
// this will use a system timer under the hood, so no thread is consumed while
// waiting
await Task.Delay(retryInterval);
}
}
这可以与以下内容同步使用:
RepeatAsync<T, TException>(work, retryInterval).Result;
但是,您也可以启动任务,然后再等待它:
var task = RepeatAsync<T, TException>(work, retryInterval);
// do other work here
// later, if you need the result, just do
var result = task.Result;
// or, if the current method is async:
var result = await task;
// alternatively, you could just schedule some code to run asynchronously
// when the task finishes:
task.ContinueWith(t => {
if (t.IsFaulted) { /* log t.Exception */ }
else { /* success case */ }
});
考虑使用瞬态故障处理应用程序块
Microsoft企业库瞬态故障处理应用程序块允许开发人员通过添加强大的瞬态故障处理逻辑使其应用程序更具弹性。 瞬态故障是由于某些临时情况(例如网络连接问题或服务不可用)而发生的错误。 通常,如果您在短时间内重试导致瞬态错误的操作,则会发现错误已消失。
它以NuGet包的形式提供。
using Microsoft.Practices.TransientFaultHandling;
using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling;
...
// Define your retry strategy: retry 5 times, starting 1 second apart
// and adding 2 seconds to the interval each retry.
var retryStrategy = new Incremental(5, TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2));
// Define your retry policy using the retry strategy and the Windows Azure storage
// transient fault detection strategy.
var retryPolicy =
new RetryPolicy<StorageTransientErrorDetectionStrategy>(retryStrategy);
// Receive notifications about retries.
retryPolicy.Retrying += (sender, args) =>
{
// Log details of the retry.
var msg = String.Format("Retry - Count:{0}, Delay:{1}, Exception:{2}",
args.CurrentRetryCount, args.Delay, args.LastException);
Trace.WriteLine(msg, "Information");
};
try
{
// Do some work that may result in a transient fault.
retryPolicy.ExecuteAction(
() =>
{
// Your method goes here!
});
}
catch (Exception)
{
// All the retries failed.
}
如何使用计时器而不是秒表?
例如:
TimeSpan retryInterval = new TimeSpan(0, 0, 5);
DateTime startTime;
DateTime retryTime;
Timer checkInterval = new Timer();
private void waitMethod()
{
checkInterval.Interval = 1000;
checkInterval.Tick += checkInterval_Tick;
startTime = DateTime.Now;
retryTime = startTime + retryInterval;
checkInterval.Start();
}
void checkInterval_Tick(object sender, EventArgs e)
{
if (DateTime.Now >= retryTime)
{
checkInterval.Stop();
// Retry Interval Elapsed
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.