Methodenausführung bei Fehler wiederholen?

Oct 27 2020

Ich arbeite an einer Anwendung, die ständig ausgeführt werden muss und als Anforderung mehrere Versuche für bestimmte Prozesse wie Web-API- / Datenbankaufrufe durchführen sollte, für den Fall, dass die Netzwerkkonnektivität für einen Moment ausfällt oder ähnliches.

In diesem Fall muss ich ständig einen grundlegenden Algorithmus schreiben:

for (int attempt = 0; i < Config.AttemptCount; i++) {
    try {
        doSomething...;
        return true;
    } catch (Exception e) {
        Log(e);
    } finally {
        if (Config.WaitTimeForRetry > 0)
            Thread.Sleep(Config.WaitTimeForRetry);
    }
}

return false;

Dies ist natürlich das grundlegendste Beispiel, aber es gibt andere, bei denen ich tatsächliche Objekte zurückgebe, schwere Operationen ausführe usw. Ich hatte kürzlich die Idee, eine einzige Methode zu entwickeln, die diesen Algorithmus für mich ausführen kann, damit ich mich auf das konzentrieren kann Gesamtfunktionalität bei jeder Implementierung stattdessen. Nachdem dies gesagt ist, präsentiere ich Ihnen eine Methode, für die ich einen besseren Namen brauche und die wahrscheinlich eine viel bessere Implementierung benötigt, oder die durch etwas ersetzt werden sollte, das bereits existiert, wenn so etwas existiert, weil ich das Rad viel neu erfinde. aber trotzdem ist es hier.

public static TOut RunProcessWithMultipleAttempts<TIn, TOut>(int numberOfAttempts, int waitTimeInMilliseconds, TIn input, Func<TIn, TOut> process) {
    TOut result = default;
    while (numberOfAttempts-- > 0) {
        try {
            result = process.Invoke(input);
            break;
        } catch (Exception e) {
            Log(e);
        } finally {
            if (waitTimeInMilliseconds > 0)
                Thread.Sleep(waitTimeInMilliseconds);
        }
    }

    return result;
}

Um dies zu verwenden, würde ich eine Methode schreiben, die die Arbeit erledigt, die ich ausführen möchte:

static int attempts = 0;
private static string TrySomething(int i) {
    for (int index = 0; index < i; index++)
        if (attempts++ < 2)
            throw new Exception("Your request was denied.");

    return "Your request was successful.";
}

Ich würde dann die RunProcessWithMultipleAttemptsMethode verwenden, um es auszuführen:

static void Main(string[] args) {
    Console.WriteLine(RunProcessWithMultipleAttempts(3, 1000, 10, TrySomething));

    // Prevent the console from closing.
    Console.ReadKey();
}

Ersetzen Sie in diesem Beispiel den Log(e)Anruf durch Console.WriteLine(e), damit er auf Ihrem lokalen Computer ausgeführt werden kann.


Ein paar Fragen in meinem Kopf:

  • Wie schwer ist das zu skalieren?
  • Was sind die Nachteile dieser Methode?
  • Welche Alternativen gibt es?
  • Ist dieser Code leicht zu verstehen?
  • Nicht nur bei der endgültigen Verwendung, sondern auch bei der Erstimplementierung?

Oh, und vielleicht meine größte Frage, wenn ich diese Implementierung beibehalten würde:

Was wäre ein prägnanterer und klarerer Name für diese Methode?

Antworten

2 PeterCsala Oct 27 2020 at 14:48

Wie schwer ist das zu skalieren?

Entschuldigung, aber ich verstehe nicht, was du hier meinst. Wie möchten Sie eine Methode skalieren?

Was sind die Nachteile dieser Methode?

  • Es funktioniert nicht mit Action

  • Es funktioniert nicht mit Func<T1, T2, TResult>

  • Es funktioniert nicht mit Func<Task>

  • Es funktioniert nicht mit Func<Task<T>>

  • Es blockiert den aufrufenden Thread unnötig ( Thread.Sleep)

  • Sie müssen Ausnahme auslösen Neuversuch zu erzwingen (kann keine andere Bedingung verwenden, wie Result != true)

  • Es schluckt die Ausnahme

    • Im schlimmsten Fall, wenn alle Versuche fehlschlagen, wird defaultanstelle der Ausnahme ein a zurückgegeben
  • Es ist nicht möglich, einen exponentiellen Backoff-Algorithmus zu verwenden

  • Es ist keine unendliche Wiederholung möglich (ein weiterer Versuch wird ausgeführt, bis er erfolgreich ist).

  • Es verwendet keine Stornierungs Konzept

  • Es werden keine Debug-Informationen bereitgestellt (z. B. wie oft der Wiederholungsversuch durchgeführt wurde).

Welche Alternativen gibt es?

  • Pollys Wiederholung << Die vorgeschlagene
  • EnterpriseLibrary.TransientFaultHandling.Core

Ist dieser Code leicht zu verstehen?

Für mich ja.

Nicht nur bei der endgültigen Verwendung, sondern auch bei der Erstimplementierung?

Ist das eine Frage?

Was wäre ein prägnanterer und klarerer Name für diese Methode?

  • ExecuteWithRetry
  • ExecuteAtMostNTimes
  • RetryFunction
  • PerformCallWithRetryPolicy
  • usw.