我们目前有一个天真的RetryWrapper,它会在发生异常时重试给定的函数:
public T Repeat<T, TException>(Func<T> work, TimeSpan retryInterval, int maxExecutionCount = 3) where TException : Exception
{
...
对于retryInterval,我们使用以下逻辑来&#34;等待&#34;在下一次尝试之前。
_stopwatch.Start();
while (_stopwatch.Elapsed <= retryInterval)
{
// do nothing but actuallky it does! lots of CPU usage specially if retryInterval is high
}
_stopwatch.Reset();
我不是特别喜欢这种逻辑,理想情况下我更希望重试逻辑不会发生在主线程上,你能想到更好的方法吗?
注意:我很乐意考虑.Net&gt; = 3.5
的答案答案 0 :(得分:3)
只要您的方法签名返回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 */ }
});
答案 1 :(得分:2)
考虑使用Transient Fault Handling Application Block
Microsoft企业库瞬态故障处理应用程序 Block允许开发人员通过添加使应用程序更具弹性 强大的瞬态故障处理逻辑。瞬态故障是错误 由于某些临时条件(如网络)而发生的情况 连接问题或服务不可用。通常,如果您重试 短时间内导致瞬态错误的操作, 你发现错误消失了。
它可以作为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.
}
答案 2 :(得分:0)
如何使用计时器代替秒表?
例如:
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
}
}