偶尔我需要在放弃之前多次重试一次手术.我的代码是这样的:
int retries = 3;
while(true) {
try {
DoSomething();
break; // success!
} catch {
if(--retries == 0) throw;
else Thread.Sleep(1000);
}
}
Run Code Online (Sandbox Code Playgroud)
我想在一般的重试函数中重写它,如:
TryThreeTimes(DoSomething);
Run Code Online (Sandbox Code Playgroud)
在C#中有可能吗?该TryThreeTimes()方法的代码是什么?
预告:伙计们,这个问题不是关于如何实施重试政策.这是关于正确完成TPL数据流块.
这个问题主要是我之前在ITargetBlock中重试策略的问题的延续.这个问题的答案是@ svick使用TransformBlock(源)和TransformManyBlock(目标)的智能解决方案.剩下的唯一问题是以正确的方式完成此块:等待所有重试首先完成,然后完成目标块.这是我最终得到的结果(它只是一个片段,不要过多关注非线程安全retries集):
var retries = new HashSet<RetryingMessage<TInput>>();
TransformManyBlock<RetryableMessage<TInput>, TOutput> target = null;
target = new TransformManyBlock<RetryableMessage<TInput>, TOutput>(
async message =>
{
try
{
var result = new[] { await transform(message.Data) };
retries.Remove(message);
return result;
}
catch (Exception ex)
{
message.Exceptions.Add(ex);
if (message.RetriesRemaining == 0)
{
if (failureHandler != null)
failureHandler(message.Exceptions);
retries.Remove(message);
}
else
{
retries.Add(message);
message.RetriesRemaining--;
Task.Delay(retryDelay)
.ContinueWith(_ => target.Post(message));
}
return null;
}
}, dataflowBlockOptions);
source.LinkTo(target);
source.Completion.ContinueWith(async …Run Code Online (Sandbox Code Playgroud) 数据处理管道和瞬态故障处理似乎是相辅相成的,所以我很想看看能否获得两个最佳的库,分别是TPL Dataflow和Polly,才能很好地协同工作。
首先,我想将错误处理策略应用于ActionBlock。理想情况下,我想将其封装在具有如下签名的块创建方法中:
ITargetBlock<T> CreatePollyBlock<T>(
Action<T> act, ExecutionDataflowBlockOptions opts, Polly.Policy policy)
Run Code Online (Sandbox Code Playgroud)
从中简单地policy.Execute进行操作就足够容易了ActionBlock,但是我有以下两个要求:
ExecutionDataflowBlockOptions.MaxDegreeOfParallelism已设置,我不希望等待重试的项目根据该最大值进行“计数”。为了满足这些要求,我想我需要一个“内部” ActionBlock与用户提供的ExecutionDataflowBlockOptions应用,并且一些“外部”块帖项内部块,并应用任何等待和重试逻辑(或任何策略规定)外内部块的上下文。这是我的第一次尝试:
// wrapper that provides a data item with mechanism to await completion
public class WorkItem<T>
{
private readonly TaskCompletionSource<byte> _tcs = new TaskCompletionSource<byte>();
public T Data { get; set; }
public Task Completion => _tcs.Task;
public void SetCompleted() => _tcs.SetResult(0);
public void SetFailed(Exception ex) => _tcs.SetException(ex);
} …Run Code Online (Sandbox Code Playgroud)