Cleanest way to write retry logic?

前端 未结 29 2567
旧巷少年郎
旧巷少年郎 2020-11-22 03:01

Occasionally I have a need to retry an operation several times before giving up. My code is like:

int retries = 3;
while(true) {
  try {
    DoSomething();
         


        
相关标签:
29条回答
  • 2020-11-22 03:25

    Blanket catch statements that simply retry the same call can be dangerous if used as a general exception handling mechanism. Having said that, here's a lambda-based retry wrapper that you can use with any method. I chose to factor the number of retries and the retry timeout out as parameters for a bit more flexibility:

    public static class Retry
    {
        public static void Do(
            Action action,
            TimeSpan retryInterval,
            int maxAttemptCount = 3)
        {
            Do<object>(() =>
            {
                action();
                return null;
            }, retryInterval, maxAttemptCount);
        }
    
        public static T Do<T>(
            Func<T> action,
            TimeSpan retryInterval,
            int maxAttemptCount = 3)
        {
            var exceptions = new List<Exception>();
    
            for (int attempted = 0; attempted < maxAttemptCount; attempted++)
            {
                try
                {
                    if (attempted > 0)
                    {
                        Thread.Sleep(retryInterval);
                    }
                    return action();
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }
            }
            throw new AggregateException(exceptions);
        }
    }
    

    You can now use this utility method to perform retry logic:

    Retry.Do(() => SomeFunctionThatCanFail(), TimeSpan.FromSeconds(1));
    

    or:

    Retry.Do(SomeFunctionThatCanFail, TimeSpan.FromSeconds(1));
    

    or:

    int result = Retry.Do(SomeFunctionWhichReturnsInt, TimeSpan.FromSeconds(1), 4);
    

    Or you could even make an async overload.

    0 讨论(0)
  • 2020-11-22 03:25

    Do it simple in C#, Java or other languages:

      internal class ShouldRetryHandler {
        private static int RETRIES_MAX_NUMBER = 3;
        private static int numberTryes;
    
        public static bool shouldRetry() {
            var statusRetry = false;
    
            if (numberTryes< RETRIES_MAX_NUMBER) {
                numberTryes++;
                statusRetry = true;
                //log msg -> 'retry number' + numberTryes
    
            }
    
            else {
                statusRetry = false;
                //log msg -> 'reached retry number limit' 
            }
    
            return statusRetry;
        }
    }
    

    and use it in your code very simple:

     void simpleMethod(){
        //some code
    
        if(ShouldRetryHandler.shouldRetry()){
        //do some repetitive work
         }
    
        //some code    
        }
    

    or you can use it in recursive methods:

    void recursiveMethod(){
        //some code
    
        if(ShouldRetryHandler.shouldRetry()){
        recursiveMethod();
         }
    
        //some code    
        }
    
    0 讨论(0)
  • 2020-11-22 03:27

    Retry helper: a generic java implementation that contains both returnable and void type retries.

    import java.util.function.Supplier;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class RetryHelper {
      private static final Logger log = LoggerFactory.getLogger(RetryHelper.class);
      private int retryWaitInMS;
      private int maxRetries;
    
      public RetryHelper() {
        this.retryWaitInMS = 300;
        this.maxRetries = 3;
      }
    
      public RetryHelper(int maxRetry) {
        this.maxRetries = maxRetry;
        this.retryWaitInMS = 300;
      }
    
      public RetryHelper(int retryWaitInSeconds, int maxRetry) {
        this.retryWaitInMS = retryWaitInSeconds;
        this.maxRetries = maxRetry;
      }
    
      public <T> T retryAndReturn(Supplier<T> supplier) {
        try {
          return supplier.get();
        } catch (Exception var3) {
          return this.retrySupplier(supplier);
        }
      }
    
      public void retry(Runnable runnable) {
        try {
          runnable.run();
        } catch (Exception var3) {
          this.retrySupplier(() -> {
            runnable.run();
            return null;
          });
        }
    
      }
    
      private <T> T retrySupplier(Supplier<T> supplier) {
        log.error("Failed <TASK>, will be retried " + this.maxRetries + " times.");
        int retryCounter = 0;
    
        while(retryCounter < this.maxRetries) {
          try {
            return supplier.get();
          } catch (Exception var6) {
            ++retryCounter;
            log.error("<TASK> failed on retry: " + retryCounter + " of " + this.maxRetries + " with error: " + var6.getMessage());
            if (retryCounter >= this.maxRetries) {
              log.error("Max retries exceeded.");
              throw var6;
            }
    
            try {
              Thread.sleep((long)this.retryWaitInMS);
            } catch (InterruptedException var5) {
              var5.printStackTrace();
            }
          }
        }
    
        return supplier.get();
      }
    
      public int getRetryWaitInMS() {
        return this.retryWaitInMS;
      }
    
      public int getMaxRetries() {
        return this.maxRetries;
      }
    }
    
    

    Usage:

        try {
          returnValue = new RetryHelper().retryAndReturn(() -> performSomeTask(args));
          //or no return type:
          new RetryHelper().retry(() -> mytask(args));
        } catch(Exception ex){
          log.error(e.getMessage());
          throw new CustomException();
        }
    
    0 讨论(0)
  • 2020-11-22 03:28
    public void TryThreeTimes(Action action)
    {
        var tries = 3;
        while (true) {
            try {
                action();
                break; // success!
            } catch {
                if (--tries == 0)
                    throw;
                Thread.Sleep(1000);
            }
        }
    }
    

    Then you would call:

    TryThreeTimes(DoSomething);
    

    ...or alternatively...

    TryThreeTimes(() => DoSomethingElse(withLocalVariable));
    

    A more flexible option:

    public void DoWithRetry(Action action, TimeSpan sleepPeriod, int tryCount = 3)
    {
        if (tryCount <= 0)
            throw new ArgumentOutOfRangeException(nameof(tryCount));
    
        while (true) {
            try {
                action();
                break; // success!
            } catch {
                if (--tryCount == 0)
                    throw;
                Thread.Sleep(sleepPeriod);
            }
       }
    }
    

    To be used as:

    DoWithRetry(DoSomething, TimeSpan.FromSeconds(2), tryCount: 10);
    

    A more modern version with support for async/await:

    public async Task DoWithRetryAsync(Func<Task> action, TimeSpan sleepPeriod, int tryCount = 3)
    {
        if (tryCount <= 0)
            throw new ArgumentOutOfRangeException(nameof(tryCount));
    
        while (true) {
            try {
                await action();
                return; // success!
            } catch {
                if (--tryCount == 0)
                    throw;
                await Task.Delay(sleepPeriod);
            }
       }
    }
    

    To be used as:

    await DoWithRetryAsync(DoSomethingAsync, TimeSpan.FromSeconds(2), tryCount: 10);
    
    0 讨论(0)
  • 2020-11-22 03:29

    The Transient Fault Handling Application Block provides an extensible collection of retry strategies including:

    • Incremental
    • Fixed interval
    • Exponential back-off

    It also includes a collection of error detection strategies for cloud-based services.

    For more information see this chapter of the Developer's Guide.

    Available via NuGet (search for 'topaz').

    0 讨论(0)
  • 2020-11-22 03:29

    Exponential backoff is a good retry strategy than simply trying x number of times. You can use a library like Polly to implement it.

    0 讨论(0)
提交回复
热议问题