Design pattern for “retrying” logic that failed?

后端 未结 11 1297
挽巷
挽巷 2020-12-07 16:10

I\'m writing some reconnect logic to periodically attempt to establish a connection to a remote endpoint which went down. Essentially, the code looks like this:



        
相关标签:
11条回答
  • 2020-12-07 16:48

    I really like this Java 8 code from this blog and you don't need any extra library on your classpath.

    You only need to pass a function to the retry class.

    @Slf4j
    public class RetryCommand<T> {
    
        private int maxRetries;
    
        RetryCommand(int maxRetries)
        {
            this.maxRetries = maxRetries;
        }
    
        // Takes a function and executes it, if fails, passes the function to the retry command
        public T run(Supplier<T> function) {
            try {
                return function.get();
            } catch (Exception e) {
                log.error("FAILED - Command failed, will be retried " + maxRetries + " times.");
                return retry(function);
            }
        }
    
        private T retry(Supplier<T> function) throws RuntimeException {
    
            int retryCounter = 0;
            while (retryCounter < maxRetries) {
                try {
                    return function.get();
                } catch (Exception ex) {
                    retryCounter++;
                    log.error("FAILED - Command failed on retry " + retryCounter + " of " + maxRetries, ex);
                    if (retryCounter >= maxRetries) {
                        log.error("Max retries exceeded.");
                        break;
                    }
                }
            }
            throw new RuntimeException("Command failed on all of " + maxRetries + " retries");
        }
    }
    

    And to use it:

    new RetryCommand<>(5).run(() -> client.getThatThing(id));
    
    0 讨论(0)
  • 2020-12-07 16:51

    Shameless plug: I have implemented some classes to allow retrying operations. The library is not made available yet, but you may fork it on github. And a fork exists.

    It allows building a Retryer with various flexible strategies. For example:

    Retryer retryer = 
        RetryerBuilder.newBuilder()
                      .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECOND))
                      .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                      .retryIfExceptionOfType(IOException.class)
                      .build();
    

    And you can then execute a callable (or several ones) with the Retryer:

    retryer.call(new Callable<Void>() {
        public Void call() throws IOException {
            connection = newConnection();
            return null;
        }
    }
    
    0 讨论(0)
  • 2020-12-07 16:56

    You can also create a wrapper function that just does a loop over the intended operation and when is done just break out of the loop.

    public static void main(String[] args) {
        retryMySpecialOperation(7);
    }
    
    private static void retryMySpecialOperation(int retries) {
        for (int i = 1; i <= retries; i++) {
            try {
                specialOperation();
                break;
            }
            catch (Exception e) {
                System.out.println(String.format("Failed operation. Retry %d", i));
            }
        }
    }
    
    private static void specialOperation() throws Exception {
        if ((int) (Math.random()*100) % 2 == 0) {
            throw new Exception("Operation failed");
        }
        System.out.println("Operation successful");
    }
    
    0 讨论(0)
  • 2020-12-07 17:00

    I'm using AOP and Java annotations. There is a ready-made mechanism in jcabi-aspects (I'm a developer):

    @RetryOnFailure(attempts = 3, delay = 1, unit = TimeUnit.SECONDS)
    public void establishConnection() {
      this.connection = newConnection();
    }
    

    ps. You can also try RetryScalar from Cactoos.

    0 讨论(0)
  • 2020-12-07 17:01

    One library worth checkout out is Sarge, which automatically performs retries according to a defined plan.

    0 讨论(0)
  • 2020-12-07 17:02

    there is nothing special in retrying at all - take this class as example http://www.docjar.com/html/api/org/springframework/jms/listener/DefaultMessageListenerContainer.java.html As you can see even spring developers still writing code for retry-ing - line 791... there is no such special pattern AFAIK..

    What i can advice to deal with resources is to take apache commons pool library - check this http://commons.apache.org/pool/apidocs/org/apache/commons/pool/impl/GenericObjectPool.html and visit http://commons.apache.org/pool

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