问题描述
我想实现一个重试任务,该任务执行之前失败的任务操作并重复它.
I'd like to implement a retry task that takes the previous failing tasks action and repeat it.
这是我目前所拥有的.然而,它只是重复了任务出错的事实,而不是真正再次触发任务的动作.
This is what I have so far. However it just repeats the fact that the task is in fault rather than actually firing the action of the task again.
public static async Task<T> Retry<T>(this Task<T> task, int retryCount, int delay, TaskCompletionSource<T> tcs = null)
{
if (tcs == null)
{
tcs = new TaskCompletionSource<T>();
}
await task.ContinueWith(async _original =>
{
if (_original.IsFaulted)
{
if (retryCount == 0)
{
tcs.SetException(_original.Exception.InnerExceptions);
}
else
{
Console.WriteLine("Unhandled exception. Retrying...");
await Task.Delay(delay).ContinueWith(async t =>
{
await Retry(task, retryCount - 1, delay, tcs);
});
}
}
else
tcs.SetResult(_original.Result);
});
return await tcs.Task;
}
我试图通过一点反思来获得行动.然而,似乎一旦任务完成,动作就会被设置为空.
I tried to get the action with a little reflection. However it seems that once the task is completed the action is set to null.
var action = task
.GetType()
.GetField("m_action", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(task) as Action;
理想情况下,我希望我的实现如下所示:
Ideally I would like my implementation to look like this:
try
{
await MakeFailure().Retry(5, 1000);
}
catch (Exception ex)
{
Console.WriteLine("I had an exception");
}
这可能是不可能的,但我想在将代码重构为 Retry(Func task)
This may not be possible but I'd like to make sure before refactoring the code to a Retry(Func<T> task)
推荐答案
考虑您的类型.Task
代表一个异步操作.在异步世界中,Task
代表一个异步操作已经开始.Task
不是你可以重试"的.
Consider your types. Task
represents an asynchronous operation. In the asynchronous world, Task
represents an asynchronous operation that has already started. Task
is not something you can "retry".
另一方面,Func
表示可以启动的异步操作.或者重新启动.这就是您需要处理的内容.
On the other hand, Func<Task>
represents an asynchronous operation that can be started. Or restarted. That's what you need to work with.
使用适当的类型后,代码很简单:
Once you are using the appropriate type, the code is straightforward:
public static async Task<T> Retry<T>(Func<Task<T>> action, int retryCount, int delay)
{
while (retryCount > 0)
{
try
{
return await action().ConfigureAwait(false);
}
catch (Exception ex)
{
await Task.Delay(delay).ConfigureAwait(false);
--retryCount;
}
}
return await action().ConfigureAwait(false);
}
像其他回答者一样,我建议您使用实际为此设计的库.瞬态故障处理应用程序块和Polly 就是两个很好的例子.
Like the other answerer, I recommend you use a library that was actually designed for this. The Transient Fault Handling Application Block and Polly are two good examples.
这篇关于重试之前的任务操作 TPL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!