Retry logic with CompletableFuture

后端 未结 7 2145
别跟我提以往
别跟我提以往 2021-01-31 18:26

I need to submit a task in an async framework I\'m working on, but I need to catch for exceptions, and retry the same task multiple times before \"aborting\".

The code I

7条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-31 19:19

    I think I was successfully. Here's an example class I created and the test code:


    RetriableTask.java

    public class RetriableTask
    {
        protected static final int MAX_RETRIES = 10;
        protected int retries = 0;
        protected int n = 0;
        protected CompletableFuture future = new CompletableFuture();
    
        public RetriableTask(int number) {
            n = number;
        }
    
        public CompletableFuture executeAsync() {
            // Create a failure within variable timeout
            Duration timeoutInMilliseconds = Duration.ofMillis(1*(int)Math.pow(2, retries));
            CompletableFuture timeoutFuture = Utils.failAfter(timeoutInMilliseconds);
    
            // Create a dummy future and complete only if (n > 5 && retries > 5) so we can test for both completion and timeouts. 
            // In real application this should be a real future
            final CompletableFuture taskFuture = new CompletableFuture<>();
            if (n > 5 && retries > 5)
                taskFuture.complete(retries * n);
    
            // Attach the failure future to the task future, and perform a check on completion
            taskFuture.applyToEither(timeoutFuture, Function.identity())
                .whenCompleteAsync((result, exception) -> {
                    if (exception == null) {
                        future.complete(result);
                    } else {
                        retries++;
                        if (retries >= MAX_RETRIES) {
                            future.completeExceptionally(exception);
                        } else {
                            executeAsync();
                        }
                    }
                });
    
            // Return the future    
            return future;
        }
    }
    

    Usage

    int size = 10;
    System.out.println("generating...");
    List tasks = new ArrayList<>();
    for (int i = 0; i < size; i++) {
        tasks.add(new RetriableTask(i));
    }
    
    System.out.println("issuing...");
    List> futures = new ArrayList<>();
    for (int i = 0; i < size; i++) {
        futures.add(tasks.get(i).executeAsync());
    }
    
    System.out.println("Waiting...");
    for (int i = 0; i < size; i++) {
        try {
            CompletableFuture future = futures.get(i);
            int result = future.get();
            System.out.println(i + " result is " + result);
        } catch (Exception ex) {
            System.out.println(i + " I got exception!");
        }
    }
    System.out.println("Done waiting...");
    

    Output

    generating...
    issuing...
    Waiting...
    0 I got exception!
    1 I got exception!
    2 I got exception!
    3 I got exception!
    4 I got exception!
    5 I got exception!
    6 result is 36
    7 result is 42
    8 result is 48
    9 result is 54
    Done waiting...
    

    Main idea and some glue code (failAfter function) come from here.

    Any other suggestions or improvement are welcome.

提交回复
热议问题