In the previous study of fault tolerance mechanism theory, we found that failback automatic recovery is one of the processing methods. Spring-retry is the middleware implementing failback. Let’s start learning about spring-retry

Basic framework Examples

The framework is introduced

  • The RetryTemplate, the retry template, is the overall process entry into the Spring-Retry framework
  • The RetryCallback interface encapsulates the service code. After failback, the RetryCallback interface is invoked again
  • RetryPolicy, the RetryPolicy, describes how the RetryCallback interface will be called

Use the Spring Retry example

public class RetryTemplateDemo {
	
	/** ** business code */
	private static String business(a) throws Exception {
		System.out.println("begin...");
		if (true) {
			throw new Exception();
		}
		System.out.println("end...");
		return "success";
	}
	
	public static void main(String[] args) throws Exception {
		RetryTemplate template = new RetryTemplate();
		SimpleRetryPolicy policy = new SimpleRetryPolicy(3);
		template.setRetryPolicy(policy);
		RetryCallback<String, Exception> retryCallback = (context) -> {
			returnbusiness(); }; String result = template.execute(retryCallback); System.out.println(result); }}Copy the code

The test results

22:24:53.746 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=0
begin...
22:24:53.751 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=1
22:24:53.751 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=1
begin...
22:24:53.751 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=2
22:24:53.751 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=2
begin...
22:24:53.751 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=3
22:24:53.751 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry failed last attempt: count=3
Exception in thread "main" java.lang.Exception
	at priv.dengjili.spring.retry.demo.test.RetryTemplateDemo5.business(RetryTemplateDemo5.java:44)
	at priv.dengjili.spring.retry.demo.test.RetryTemplateDemo5.lambda$0(RetryTemplateDemo5.java:33)
	at priv.dengjili.spring.retry.demo.test.RetryTemplateDemo5$$Lambda$1/1221555852.doWithRetry(Unknown Source)
	at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:329)
	at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:209)
	at priv.dengjili.spring.retry.demo.test.RetryTemplateDemo5.main(RetryTemplateDemo5.java:35)
Copy the code

The result shows that the original service code will throw an exception, and the SimpleRetryPolicy is set to retry three times. The test results show that the results are consistent

RetryPolicy provides other policy implementations:

  • NeverRetryPolicy: RetryCallback is allowed to be called only once and retry is not allowed.
  • AlwaysRetryPolicy: allows infinite retries until success. Improper logic in this way will lead to an infinite loop.
  • SimpleRetryPolicy: specifies a fixed retry policy. The maximum number of retries is three by default. RetryTemplate Specifies the default policy.
  • TimeoutRetryPolicy: TimeoutRetryPolicy. The default timeout is 1 second. Retries are allowed within the specified timeout.
  • CircuitBreakerRetryPolicy: fusing features of retry strategy, it is necessary to set up three parameters openTimeout, resetTimeout and delegate;
  • A CompositeRetryPolicy is composed of two retry policies. An optimistic retry policy is implemented as long as one policy allows retry, and a pessimistic retry policy is implemented as long as one policy does not allow retry. Regardless of the two retry policies, each policy in the CompositeRetryPolicy executes.

For detailed examples, please refer to github.com/spring-proj…

RecoveryCallback Recovery policy

  • RecoveryCallback, which provides a compensation method to recover after all retries fail
public class RetryTemplateDemo {
	
	/** ** business code */
	private static String business(a) throws Exception {
		System.out.println("begin...");
		if (true) {
			throw new Exception();
		}
		System.out.println("end...");
		return "success";
	}
	
	public static void main(String[] args) throws Exception {
		RetryTemplate template = new RetryTemplate();
		SimpleRetryPolicy policy = new SimpleRetryPolicy(3);
		template.setRetryPolicy(policy);
		RetryCallback<String, Exception> retryCallback = (context) -> {
			return business();
		};
		RecoveryCallback<String> recoveryCallback = (context) -> {
			return "default_sucesss"; }; String result = template.execute(retryCallback, recoveryCallback); System.out.println(result); }}Copy the code

The test results

22:45:37.823 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=0
begin...
22:45:37.826 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=1
22:45:37.826 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=1
begin...
22:45:37.827 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=2
22:45:37.827 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=2
begin...
22:45:37.827 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=3
22:45:37.827 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry failed last attempt: count=3
default_sucesss
Copy the code

The result shows that the original service code throws an exception and the SimpleRetryPolicy is set to retry for three times. The result is consistent with the RecoveryCallback interface method

Stateful retry

HTTP is stateless, that is, there is no relationship or influence between two calls. Stateful means there is influence between calls. For example, if the failure is due to transaction resources, data problems may occur during multiple calls and the exception cannot be retried immediately. Spring-retry provides the RetryState object, as an example

public class RetryTemplateDemo5 {
	
	/** ** business code */
	private static String business(a) throws Exception {
		System.out.println("begin...");
		if (true) {
			throw new Exception();
		}
		System.out.println("end...");
		return "success";
	}
	
	public static void main(String[] args) throws Exception {
		RetryTemplate template = new RetryTemplate();
		SimpleRetryPolicy policy = new SimpleRetryPolicy(3);
		template.setRetryPolicy(policy);
		RetryCallback<String, Exception> retryCallback = (context) -> {
			return business();
		};
		RecoveryCallback<String> recoveryCallback = (context) -> {
			return "default_sucesss";
		};
		RetryState state = new DefaultRetryState("unique call"); String result = template.execute(retryCallback, recoveryCallback, state); System.out.println(result); }}Copy the code

The test results

22:56:59.883 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=0
begin...
22:56:59.887 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=1
22:56:59.887 [main] DEBUG org.springframework.retry.support.RetryTemplate - Rethrow in retry for policy: count=1
Exception in thread "main" java.lang.Exception
	at priv.dengjili.spring.retry.demo.test.RetryTemplateDemo5.business(RetryTemplateDemo5.java:30)
	at priv.dengjili.spring.retry.demo.test.RetryTemplateDemo5.lambda$0(RetryTemplateDemo5.java:41)
	at priv.dengjili.spring.retry.demo.test.RetryTemplateDemo5$$Lambda$1/2104457164.doWithRetry(Unknown Source)
	at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:329)
	at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:255)
	at priv.dengjili.spring.retry.demo.test.RetryTemplateDemo5.main(RetryTemplateDemo5.java:47)
Copy the code

The tests were as expected

RetryListener listener

Provides three places to listen

public class RetryTemplateDemo5 {
	
	/** ** business code */
	private static String business(a) throws Exception {
		System.out.println("begin...");
		if (true) {
			throw new Exception();
		}
		System.out.println("end...");
		return "success";
	}
	
	public static void main(String[] args) throws Exception {
		RetryTemplate template = new RetryTemplate();
		SimpleRetryPolicy policy = new SimpleRetryPolicy(3);
		template.setRetryPolicy(policy);
		RetryCallback<String, Exception> retryCallback = (context) -> {
			return business();
		};
		RecoveryCallback<String> recoveryCallback = (context) -> {
			return "default_sucesss";
		};
		RetryListener listener = new RetryListener() {
			@Override
			public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
				System.out.println("open");
				// It must return true, otherwise it is finished
				return true;
			}

			@Override
			public <T, E extends Throwable> void close(RetryContext context, RetryCallback
       
         callback, Throwable throwable)
       ,> {
				System.out.println("close");
			}

			@Override
			public <T, E extends Throwable> void onError(RetryContext context, RetryCallback
       
         callback, Throwable throwable)
       ,> {
				System.out.println("onError");
			}};
		// Multiple RetryListeners can be set
		template.setListeners(newRetryListener[] {listener}); String result = template.execute(retryCallback, recoveryCallback); System.out.println(result); }}Copy the code

The test results

open
23: 08:58.601 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=0
begin...
onError
23: 08:58.605 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=1
23: 08:58.606 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=1
begin...
onError
23: 08:58.606 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=2
23: 08:58.606 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry: count=2
begin...
onError
23: 08:58.606 [main] DEBUG org.springframework.retry.support.RetryTemplate - Checking for rethrow: count=3
23: 08:58.606 [main] DEBUG org.springframework.retry.support.RetryTemplate - Retry failed last attempt: count=3
close
default_sucesss
Copy the code

The tests were as expected

Other instructions

Starting with version 1.3, a simpler configuration of RetryTemplate is also available, as follows:

RetryTemplate.builder()
      .maxAttempts(10)
      .exponentialBackoff(100.2.10000)
      .retryOn(IOException.class)
      .traversingCauses()
      .build();

RetryTemplate.builder()
      .fixedBackoff(10)
      .withinMillis(3000)
      .build();

RetryTemplate.builder()
      .infiniteRetry()
      .retryOn(IOException.class)
      .uniformRandomBackoff(1000.3000)
      .build();
Copy the code

Or use declarative programming, annotated as follows: eg1:

@Configuration
@EnableRetry
public class Application {

    @Bean
    public Service service(a) {
        return new Service();
    }

    @Bean public RetryListener retryListener1(a) {
        return new RetryListener() {...}
    }

    @Bean public RetryListener retryListener2(a) {
        return newRetryListener() {... }}}@Service
class Service {
    @Retryable(RemoteAccessException.class)
    public service(a) {
        // ... do something}}Copy the code

Eg2:

@Service
class Service {
    @Retryable(maxAttempts=12, backoff=@Backoff(delay=100, maxDelay=500))
    public service(a) {
        // ... do something}}Copy the code

Eg3:

@Service
class Service {
    @Retryable(recover = "service1Recover", value = RemoteAccessException.class)
    public void service1(String str1, String str2) {
        // ... do something
    }

    @Retryable(recover = "service2Recover", value = RemoteAccessException.class)
    public void service2(String str1, String str2) {
        // ... do something
    }

    @Recover
    public void service1Recover(RemoteAccessException e, String str1, String str2) {
        // ... error handling making use of original args if required
    }

    @Recover
    public void service2Recover(RemoteAccessException e, String str1, String str2) {
        // ... error handling making use of original args if required}}Copy the code

Introduction to the source code

The above is my sort out by reading the Spring – Retry the source code, source code directory https://github.com/spring-projects/spring-retry

The core code entry: org. Springframework. Retry. Support. The doExecute RetryTemplate method

reference

Blog.csdn.net/u012731081/…