Czasami zachodzi potrzeba ponownego wykonania jakiegoś kodu, w przypadku np. wyrzucenia błędu. Można samemu zaimplementować to za pomocą np. pętli, kontynuować daną operację w kolejnych iteracjach.
Problem w tym, że taki mechanizm można dość znacząco rozbudowywać. Zwykle, chcemy poczekać przed następną iteracją ponieważ szanse, że ponowna próba, natychmiast po pierwszej próbie zakończy się sukcesem jest niska. Ponadto, zdefiniowanie “niepowodzenia” też jest dość skomplikowane.
Polly to mała, ale dość rozbudowana biblioteka rozwiązująca powyższy problem. Zaczynamy od instalacji NuGet:
Install-Package Polly
W najprostszej postaci, konfiguracja może wyglądać następująco:
static void Main(string[] args) { var policy = Polly.Policy.Handle<DivideByZeroException>().Retry(); policy.Execute(DoSomething); Console.ReadLine(); } private static void DoSomething() { Console.WriteLine(DateTime.Now); throw new DivideByZeroException(); }
Na ekranie wtedy zobaczymy dwie próby:
Możemy również próbować w nieskończoność:
var policy = Polly.Policy.Handle<DivideByZeroException>().RetryForever(); policy.Execute(DoSomething);
Zwykle jest to zły pomysł i lepiej określić maksymalną liczbę prób:
var policy = Polly.Policy.Handle<DivideByZeroException>().Retry(5);
Jeśli chcemy czekać pomiędzy kolejnymi próbami, wtedy należy przekazać kolekcję TimeSpan:
var policy = Polly.Policy.Handle<DivideByZeroException>().WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3) });
WaitAndRetry przyjmuje jako parametr również metodę, określającą czas czekania dla poszczególnej iteracji:
var policy = Polly.Policy. Handle<DivideByZeroException>(). WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) );
Definiowane wyjątki można również filtrować:
Policy .Handle<SqlException>(ex => ex.Number == 1205)
Do dyspozycji jest metodą Or, która umożliwia łączenie warunków:
Policy .Handle<DivideByZeroException>() .Or<ArgumentException>()
Polly wspiera asynchroniczne wywołania za pomocą np. ExecuteAsync.