Teaser: ребята, этот вопрос не о том, как реализовать политику повтора. Это о правильном завершении блока потока данных TPL.
Этот вопрос в основном является продолжением моего предыдущего вопроса Повторить политику в ITargetBlock. Ответом на этот вопрос было решение @svick smart, которое использует TransformBlock
(источник) и TransformManyBlock
(target). Единственная проблема заключается в том, чтобы закончить этот блок правильно: дождитесь завершения всех попыток, а затем заполните целевой блок. Вот что я закончил (это просто фрагмент, не обращайте слишком много внимания на не-потоковое приложение 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 _ =>
{
while (target.InputCount > 0 || retries.Any())
await Task.Delay(100);
target.Complete();
});
Идея состоит в том, чтобы выполнить какой-то опрос и проверить, есть ли еще сообщения, ожидающие обработки, и нет сообщений, требующих повторной попытки. Но в этом решении мне не нравится идея опроса.
Да, я могу инкапсулировать логику добавления/удаления повторений в отдельный класс и даже, например, выполнить некоторое действие, когда набор попыток станет пустым, но как справиться с условием target.InputCount > 0
? Не существует такого обратного вызова, вызываемого при отсутствии ожидающих сообщений для блока, поэтому кажется, что проверка target.ItemCount
в цикле с небольшой задержкой является единственным вариантом.
Кто-нибудь знает более умный способ достичь этого?