Best Practice of Interface Retry Mechanism-Application of Guava-retrying

In project development, calling a third-party interface will cause errors in the called service due to network delays and abnormalities. The call may be successful after a few retries (such as uploading pictures). Therefore, a retry mechanism is required to retry the interface to ensure the interface’s performance. Perform normally. In addition to implementing the retry mechanism in code, guava-retry can implement this function flexibly.
github address: https://github.com/rholder/guava-retrying/tree/master/src/main/java/com/github /rholder/retry

This article first introduces how to use java code to implement the retry mechanism of the interface, and then introduces the use of guava-retry.

One, Java implements the interface retry mechanism by itself

First, you need a service, such as an image upload service:

 public boolean uploadPicture(String fileName, int count) {
    
    
        System.out.println("开始上传文件:" + fileName);
        // 模拟在第3次重试成功
        if (count == 3) {
    
    
            System.out.println("文件上传成功, 重试次数:" + count);
            return true;
        }
        // 模拟因网络等原因导致的图片上传服务超时
        return false;
    }

In the interface, it is simulated that due to a network failure, each upload operation fails. At this time, you need to retry 3 times when calling the image upload interface. The code implementation is as follows:

public void uploadFile(String fileName, int retryTimes) {
    
    
        PictureService pictureService = new PictureService();
        boolean success = pictureService.uploadPicture(fileName);
        if (retryTimes > 0) {
    
    
            int count = 1;
            while (!success && count <= retryTimes) {
    
    
                System.out.println("第-" + count + "-次重试");
                success = pictureService.uploadPicture(fileName);
                count++;

            }
        }
        return;
    }

test:

public static void main(String[] args) {
    
    
        new Test2().uploadFile("testFile", 3);
}

The test results are as follows:
Insert picture description here

It can be seen that if the result returned by the picture service interface PictureService is false, a retry will be made. The above code can initially implement the interface retry.

2. Elegant implementation of interface retry-guava-retry code combat

Although the above code can initially implement interface retry, such code is not elegant enough, and at the same time, it cannot better control the interface retry, such as whether the conditions for retrying are controllable, the number of retries, and the number of retries. Strategy selection and so on, and guava-retry provides this simple and implementable interface retry mechanism.
Let's first look at how guava-retry implements interface retry.

1 、 pom.xml

First introduce the jar package:

<dependency>
      <groupId>com.github.rholder</groupId>
      <artifactId>guava-retrying</artifactId>
      <version>2.0.0</version>
</dependency>

2. Code implementation

package com.hrms.csdn;

import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * Created by wanggenshen
 * Date: on 2019/1/4 00:42.
 * Description: XXX
 */
public class Test {
    
    

    static Retryer<Boolean> retryer;

   static {
    
    
        retryer = RetryerBuilder.<Boolean>newBuilder()
                .retryIfException() // 抛出异常会进行重试
                .retryIfResult(Predicates.equalTo(false)) // 如果接口返回的结果不符合预期,也需要重试
                .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS)) // 重试策略, 此处设置的是重试间隔时间
                .withStopStrategy(StopStrategies.stopAfterAttempt(5)) // 重试次数
                .build();
    }


    public boolean uploadFile(String fileName) {
    
    
        try {
    
    

            return retryer.call(new Callable<Boolean>() {
    
    
                int count = 0;
                @Override
                public Boolean call() throws Exception {
    
    
                    return new PictureService().uploadPicture(fileName, count++);
                }
            });
        } catch (Exception e) {
    
    
        	e.printStackTrace();
            return false;
        }

    }


    public static void main(String[] args) {
    
    
        new Test().uploadFile("testFile");
    }
}


3. Test results:

Insert picture description here

Three, introduction to the use of guava-retry

Through actual code combat, we have learned about the implementation of guava-retry interface retry. Now let's take a look at the detailed configuration of guava-retry and how to use it better.

1、RetryerBuilder

RetryerBuilder is used to quickly generate Retryer instances, and can configure the number of retries, timeout period, etc.

2、retryIfException、retryIfRuntimeException、retryIfExceptionOfType

  • retryIfException
    retryIfException supports the Exception exception object. When a runtime exception or checked exception is thrown, it will retry, but error will not retry.

  • retryIfRuntimeException
    retryIfRuntimeException will only be retried when a Runtime exception is thrown, checked exceptions and errors will not be retried.

  • retryIfExceptionOfType
    retryIfExceptionOfType allows us to retry only when a specific exception occurs, such as NullPointerException and IllegalStateException are runtime exceptions, including custom errors

.retryIfExceptionOfType(Error.class)// 只在抛出error重试

Retry only when the specified exception occurs
.retryIfExceptionOfType(IllegalStateException.class) .retryIfExceptionOfType(NullPointerException.class)

3、retryIfResult

retryIfResult can specify your Callable method to retry when it returns, such as  
.retryIfResult(Predicates.equalTo(false)) // 返回false重试

4、WaitStrategy

Waiting time strategy, retry interval time.
The commonly used strategies are:

  • FixedWaitStrategy fixed waiting time strategy;
    .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS)
  • RandomWaitStrategy Random waiting time strategy (a minimum and maximum time can be provided, and the waiting time is a random value in the interval).
  • IncrementingWaitStrategy Incremental waiting time strategy (provide an initial value and step length, the waiting time increases with the number of retries).

5 、 StopStrategy

Stop retry strategy, three types are provided:

  • StopAfterDelayStrategy set a maximum allowable execution time; for example, set a maximum execution time of 10s, regardless of the number of task executions, as long as the maximum time is exceeded when retrying, the task will be terminated and a retry exception RetryException will be returned;
    .withStopStrategy(StopStrategies.stopAfterDelay(5, TimeUnit.SECONDS)) // 最长允许执行的时间

  • StopAfterAttemptStrategy sets the maximum number of retries. If the maximum number of retries is exceeded, the retries will be stopped and the retry exception will be returned;
    .withStopStrategy(StopStrategies.stopAfterAttempt(5)) // 重试次数

  • NeverStopStrategy does not stop. It is used in situations where it is necessary to keep training in rotation until the expected result is returned.

6 、 RetryListener

A custom retry listener can be used to record error logs asynchronously. When a retry occurs, you need to record the number of retries, results and other information, or have more expansion.

The specific usage is as follows:

public class MyRetryListener implements RetryListener {
    
    


    @Override
    public <Boolean> void onRetry(Attempt<Boolean> attempt) {
    
    
        // 距离上一次重试的时间间隔
        System.out.println("距上一次重试的间隔时间为:" + attempt.getDelaySinceFirstAttempt());
        // 重试次数
        System.out.println("重试次数: " + attempt.getAttemptNumber());
        // 重试过程是否有异常
        System.out.println("重试过程是否有异常:" + attempt.hasException());
        if (attempt.hasException()) {
    
    
            System.out.println("异常的原因:" + attempt.getExceptionCause().toString());
        }
        //重试正常返回的结果
        System.out.println("重试结果为:" + attempt.hasResult());

        System.out.println();
    }
}
static Retryer<Boolean> retryer;

 static {
    
    
        retryer = RetryerBuilder.<Boolean>newBuilder()
                .retryIfException() // 抛出异常会进行重试
                .retryIfResult(Predicates.equalTo(false)) // 如果接口返回的结果不符合预期,也需要重试
                .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS)) // 重试策略, 此处设置的是重试间隔时间
                .withStopStrategy(StopStrategies.stopAfterAttempt(5)) // 重试次数
                .withRetryListener(new MyRetryListener())
                .build();
    }

The final execution result is as follows:
Insert picture description here


Reference: https://blog.csdn.net/songhaifengshuaige/article/details/79440285

Guess you like

Origin blog.csdn.net/noaman_wgs/article/details/85940207