Teaser: Chłopaki, to pytanie nie dotyczy tego, jak zaimplementować politykę ponawiania prób. Chodzi o poprawne zakończenie bloku przepływu danych TPL.Wdrażanie poprawnego wykonania bloku do ponownej próby
To pytanie jest głównie kontynuacją mojego poprzedniego pytania Retry policy within ITargetBlock. Odpowiedzią na to pytanie było inteligentne rozwiązanie @ svick, które wykorzystuje TransformBlock
(źródło) i TransformManyBlock
(cel). Pozostaje tylko ukończyć ten blok w prawidłowej drodze:: poczekaj na zakończenie wszystkich ponownych prób, a następnie ukończ blok docelowy. Oto, co skończyło się (to tylko fragment, nie płacą zbyt wiele uwagi na zakaz THREADSAFE retries
zestawie):
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();
});
Chodzi o to, aby wykonać jakąś odpytywania i sprawdzić, czy istnieją nadal wiadomości oczekujące na przetworzenie i nie ma wiadomości, które wymagają ponowienia. Ale w tym rozwiązaniu nie podoba mi się pomysł sondowania.
Tak, można hermetyzować logikę dodawania/usuwania ponownych prób w oddzielnej klasie, a nawet np. wykonać pewne działanie, gdy zbiór ponownych prób staje się pusty, ale jak radzić sobie z warunkiem target.InputCount > 0
? Nie ma takiego wywołania zwrotnego, które zostanie wywołane, gdy nie ma oczekujących komunikatów dla bloku, więc wydaje się, że weryfikacja target.ItemCount
w pętli z małym opóźnieniem jest jedyną opcją.
Czy ktoś zna mądrzejszy sposób, aby to osiągnąć?
Wygląda na to, że ITargetBlock obsługuje powiadomienia oparte na pilocie za pośrednictwem obserwatora zwrócone przez metodę AsObserver Extension. Zobacz http://msdn.microsoft.com/en-us/library/hh160359.aspx i http://msdn.microsoft.com/en-us/library/ee850490.aspx. – JamieSee
Wygląda na to, że próbujesz używać wyjątków w normalnym przepływie programu, co jest złym zwyczajem. Wyszukiwarka Google lub szukać pod następującym temacie na SO: http://stackoverflow.com/questions/729379/why-not-use-exceptions-as-regular-flow-of-control Cała logika ponawiania powinien być w bloku try, a nie w bloku wyjątków. Nie jest to odpowiedź na twoje pytanie, ale coś, o czym myślałem, że powinieneś wiedzieć. – Nullius
@Nullius, logika ponownych prób opiera się na * wyjątkach * - ponów w przypadku przejściowego błędu. Nie sądzę, że logika ponownej próby w bloku 'try' jest dobrym pomysłem, ponieważ nie znasz typu błędu i czy ten rodzaj błędu jest przejściowy, czy też nie. – Alex