Moment For Technology

SpringBoot Practices -SpringRetry Retry framework

Posted on Dec. 1, 2022, 5:20 p.m. by Kara Fuentes
Category: The back-end Tag: The back-end Spring Boot

First, environment construction

  1. Add the SpringRetry dependency, which is implemented using AOP, so add the AOP package as well
! -- SpringRetry --
dependency
	  groupIdorg.springframework.retry/groupId
	  artifactIdspring-retry/artifactId
/dependency
dependency
	  groupIdorg.springframework/groupId
	  artifactIdspring-aspects/artifactId
/dependency
Copy the code
  1. The official documentation
    • www.baeldung.com/spring-retr...

Second, the RetryTemplate

2.1 RetryTemplate

  1. RetryTemplate encapsulates the Retry basic operation
    • org.springframework.retry.support.RetryTemplate
  2. In the RetryTemplate file, you can specify the listening, rollback policy, and retry policy
  3. Just the normal New RetryTemplate() is needed

2.2 RetryListener

  1. RetryListener specifies a callback when an error occurs during execution
    • org.springframework.retry.RetryListener
package org.springframework.retry;

public interface RetryListener {

	/** * is called only once when the task starts executing
	T, E extends Throwable boolean open(RetryContext context, RetryCallbackT, E callback);

	/** * Call at the end of the task (including retry), only once */
	T, E extends Throwable void close(RetryContext context, RetryCallbackT, E callback, Throwable throwable);

	/** * callback when an error occurs
	T, E extends Throwable void onError(RetryContext context, RetryCallbackT, E callback, Throwable throwable);
}
Copy the code
  1. Once configured, specify it in the RetryTemplate

2.3 Rollback Policy

2.3.1 FixedBackOffPolicy

  1. How much time is delayed to continue the call when an error occurs
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(1000L);
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
Copy the code
  1. Once configured, specify it in the RetryTemplate

2.3.2 ExponentialBackOffPolicy

  1. The delay is exponential after the first delay at the specified delay time when an error occurs
// Exponential rollback (s) : the first rollback is 1s, the second rollback is 2s, the third rollback is 4 seconds, and the fourth rollback is 8 seconds
ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
exponentialBackOffPolicy.setInitialInterval(1000L);
exponentialBackOffPolicy.setMultiplier(2);
retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);
Copy the code
  1. Once configured, specify it in the RetryTemplate

2.4 Retry Policy

  1. The retry policy specifies the number of retries when an error occurs
// Retry policy
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(5);
retryTemplate.setRetryPolicy(retryPolicy);
Copy the code
  1. Once configured, specify it in the RetryTemplate

2.5 RetryCallback

  1. RetryCallback is the callback that is executed when retryTemplate. Execute
    • public final T, E extends Throwable T execute(RetryCallbackT, E retryCallback) throws E

2.6 Core Usage

  1. You can use RetryTemplate for simple use
  2. Configuration retryTemplate
    • The rollback policy is ExponentialBackOffPolicy
    • Set the retry policy to SimpleRetryPolicy
    • Specify the listener, RetryListener
import com.codecoord.util.PrintUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

@Configuration
public class RetryTemplateConfig {

    /** * Inject retryTemplate */
    @Bean
    public RetryTemplate retryTemplate(a) {
        RetryTemplate retryTemplate = new RetryTemplate();

        /// Roll back fixed time (s)
       /* FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); fixedBackOffPolicy.setBackOffPeriod(1000L); retryTemplate.setBackOffPolicy(fixedBackOffPolicy); * /

        // Exponential rollback (s) : the first rollback is 1s, and the second rollback is 2s
        ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
        exponentialBackOffPolicy.setInitialInterval(1000L);
        exponentialBackOffPolicy.setMultiplier(2);
        retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);

        // Retry policy
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(5);
        retryTemplate.setRetryPolicy(retryPolicy);

        // Set the listener to open and close at startup and end, respectively
        RetryListener[] listeners = {
                new RetryListener() {
                    @Override
                    public T, E extends Throwable boolean open(RetryContext context, RetryCallbackT, E callback) {
                        PrintUtil.print("open");
                        return true;
                    }
                    @Override
                    public T, E extends Throwable void close(RetryContext context, RetryCallback
       
         callback, Throwable throwable)
       , {
                        PrintUtil.print("close");
                    }
                    @Override
                    public T, E extends Throwable void onError(RetryContext context, RetryCallback
       
         callback, Throwable throwable)
       , {
                        PrintUtil.print("onError"); }}}; retryTemplate.setListeners(listeners);returnretryTemplate; }}Copy the code
  1. Inject RetryTemplate into the Controller, or optionally into the Service
@RestController
public class SpringRetryController {
    @Resource
    private RetryTemplate retryTemplate;
    private static int count = 0;

    @RequestMapping("/retry")
    public Object retry(a) {
        try {
            count = 0;
            retryTemplate.execute((RetryCallbackVoid, RuntimeException) context - {
                // Business code
                / /...
                // Simulation throws an exception
                ++count;
                throw new RuntimeException("Throw an exception");
            });
        } catch (RuntimeException e) {
            System.out.println("Exception");
        }

        return "retry = "+ count; }}Copy the code
  1. Access the Retry interface and observe the log output
18:27:20.648 - http-nio-8888-exec-1 - open
18:27:20.649 - http-nio-8888-exec-1- retryTemplate. Execute execution18:27:20.649 - http-nio-8888-exec-1 - onError
18:27:21.658 - http-nio-8888-exec-1- retryTemplate. Execute execution18:27:21.658 - http-nio-8888-exec-1 - onError
18:27:23.670 - http-nio-8888-exec-1- retryTemplate. Execute execution18:27:23.670 - http-nio-8888-exec-1 - onError
18:27:27.679 - http-nio-8888-exec-1- retryTemplate. Execute execution18:27:27.679 - http-nio-8888-exec-1 - onError
18:27:35.681 - http-nio-8888-exec-1- retryTemplate. Execute execution18:27:35.681 - http-nio-8888-exec-1 - onError
18:27:35.681 - http-nio-8888-exec-1 - close
Copy the code

Third, EnableRetry

  1. EnableRetry Enables retry. Methods will be executed by default when specified on a class. Retry three times
  2. Define the service, enable the @enableretry annotation, and specify @retryable. Retry is referred to in the next section
import org.springframework.retry.annotation.Retryable;

public interface RetryService {

    /** * Retry method call */
    @Retryable
    void retryServiceCall(a);
}

Copy the code
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.stereotype.Service;

@EnableRetry
@Service
public class RetryServiceImpl implements RetryService {

    @Override
    public void retryServiceCall(a) {
        PrintUtil.print("Method call..");
        throw new RuntimeException("Manual exception"); }}Copy the code
  1. Service is injected into the controller
@RequestMapping("/retryAnnotation")
public Object retryAnnotation(a) {
    retryService.retryServiceCall();
    return "retryAnnotation";
}
Copy the code
  1. Retry by default
18:46:48.721 - http-nio-8888-exec-1- Method calls..18:46:49.724 - http-nio-8888-exec-1- Method calls..18:46:50.730 - http-nio-8888-exec-1- Method calls.. Java. Lang. RuntimeException: manual exceptionCopy the code

Four, Retryable

  1. Annotations for methods that need to be retried
  2. There are several properties
    • Retryable specifies the annotation parameter
      • Value: specifies the exception that occurs to retry
      • Include: Is null by default, as is value. If exclude is also null, all exceptions are retried
      • Exclude: Specifies that exceptions are not retried. The default value is empty. If include is also empty, all exceptions are retried
      • Maxtem ps: The number of retries. The default is 3
      • Backoff: Retry compensation mechanism. No default
    • @backoff annotate retry compensation policy
      • If no parameter is set, FixedBackOffPolicy is used by default and the retry time is 1000ms
      • Set delay, using FixedBackOffPolicy (when delay and maxDealy are set, retry wait is evenly distributed between these two values)
      • Set delay, maxDealy, and multiplier using ExponentialBackOffPolicy (an implementation of an exponential retry interval). A multiplier specifies a multiple of the delay, for example delay=5000L, Multiplier =2, then the first retry is 5 seconds, the second is 10 seconds, and the third is 20 seconds
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Retryable {

	/**
	 * Retry interceptor bean name to be applied for retryable method. Is mutually
	 * exclusive with other attributes.
	 * @return the retry interceptor bean name
	 */
	String interceptor(a) default "";

	/** * Exception types that are retryable. Synonym for includes(). Defaults to empty (and * if excludes is also empty all  exceptions are retried). *@return exception types to retry
	 */
	Class? extends Throwable[] value() default {};

	/**
	 * Exception types that are retryable. Defaults to empty (and if excludes is also
	 * empty all exceptions are retried).
	 * @return exception types to retry
	 */
	Class? extends Throwable[] include() default {};

	/**
	 * Exception types that are not retryable. Defaults to empty (and if includes is also
	 * empty all exceptions are retried).
	 * If includes is empty but excludes is not, all not excluded exceptions are retried
	 * @return exception types not to retry
	 */
	Class? extends Throwable[] exclude() default {};

	/**
	 * A unique label for statistics reporting. If not provided the caller may choose to
	 * ignore it, or provide a default.
	 *
	 * @return the label for the statistics
	 */
	String label(a) default "";

	/**
	 * Flag to say that the retry is stateful: i.e. exceptions are re-thrown, but the
	 * retry policy is applied with the same policy to subsequent invocations with the
	 * same arguments. If false then retryable exceptions are not re-thrown.
	 * @return true if retry is stateful, default false
	 */
	boolean stateful(a) default false;

	/ * * *@return the maximum number of attempts (including the first failure), defaults to 3
	 */
	int maxAttempts(a) default 3;

	/ * * *@return an expression evaluated to the maximum number of attempts (including the first failure), defaults to 3
	 * Overrides {@link #maxAttempts()}.
	 * @date1.2 * /
	String maxAttemptsExpression(a) default "";

	/**
	 * Specify the backoff properties for retrying this operation. The default is a
	 * simple {@link Backoff} specification with no properties - see it's documentation
	 * for defaults.
	 * @return a backoff specification
	 */
	Backoff backoff(a) default @Backoff(a);

	/**
	 * Specify an expression to be evaluated after the {@code SimpleRetryPolicy.canRetry()}
	 * returns true - can be used to conditionally suppress the retry. Only invoked after
	 * an exception is thrown. The root object for the evaluation is the last {@code Throwable}.
	 * Other beans in the context can be referenced.
	 * For example:
	 * pre class=code
	 *  {@code "message.contains('you can retry this')"}.
	 * /pre
	 * and
	 * pre class=code
	 *  {@code "@someBean.shouldRetry(#root)"}.
	 * /pre
	 * @return the expression.
	 * @date1.2 * /
	String exceptionExpression(a) default "";

	/**
	 * Bean names of retry listeners to use instead of default ones defined in Spring context
	 * @return retry listeners bean names
	 */
	String[] listeners() default {};

}
Copy the code
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Backoff {

	/**
	 * Synonym for {@link #delay()}.
	 *
	 * @return the delay in milliseconds (default 1000)
	 */
	long value(a) default 1000;

	/**
	 * A canonical backoff period. Used as an initial value in the exponential case, and
	 * as a minimum value in the uniform case.
	 * @return the initial or canonical backoff period in milliseconds (default 1000)
	 */
	long delay(a) default 0;

	/**
	 * The maximimum wait (in milliseconds) between retries. If less than the
	 * {@link #delay()} then the default of
	 * {@value org.springframework.retry.backoff.ExponentialBackOffPolicy#DEFAULT_MAX_INTERVAL}
	 * is applied.
	 *
	 * @return the maximum delay between retries (default 0 = ignored)
	 */
	long maxDelay(a) default 0;

	/**
	 * If positive, then used as a multiplier for generating the next delay for backoff.
	 *
	 * @return a multiplier to use to calculate the next backoff delay (default 0 =
	 * ignored)
	 */
	double multiplier(a) default 0;

	/**
	 * An expression evaluating to the canonical backoff period. Used as an initial value
	 * in the exponential case, and as a minimum value in the uniform case. Overrides
	 * {@link #delay()}.
	 * @return the initial or canonical backoff period in milliseconds.
	 * @date1.2 * /
	String delayExpression(a) default "";

	/**
	 * An expression evaluating to the maximimum wait (in milliseconds) between retries.
	 * If less than the {@link #delay()} then the default of
	 * {@value org.springframework.retry.backoff.ExponentialBackOffPolicy#DEFAULT_MAX_INTERVAL}
	 * is applied. Overrides {@link #maxDelay()}
	 *
	 * @return the maximum delay between retries (default 0 = ignored)
	 * @date1.2 * /
	String maxDelayExpression(a) default "";

	/**
	 * Evaluates to a vaule used as a multiplier for generating the next delay for
	 * backoff. Overrides {@link #multiplier()}.
	 *
	 * @return a multiplier expression to use to calculate the next backoff delay (default
	 * 0 = ignored)
	 * @date1.2 * /
	String multiplierExpression(a) default "";

	/**
	 * In the exponential case ({@link #multiplier()} gt; 0) set this to true to have the
	 * backoff delays randomized, so that the maximum delay is multiplier times the
	 * previous delay and the distribution is uniform between the two values.
	 *
	 * @return the flag to signal randomization is required (default false)
	 */
	boolean random(a) default false;

}
Copy the code
  1. Set the retry times, retry exception type, rollback delay, retry policy, and method listening name for the method to be retried
@Component
public class PlatformClassService {
    @retryable (// value = {Exception. Class}, // maxAttempts = 5, // Set backoff = @backoff (delay = 500), // Set callback method name to listeners = "retryListener")
    public void call(a) {
        System.out.println("call...");
        throw new RuntimeException("Manual exception"); }}Copy the code
// Initial delay of 2 seconds, and then acceptance 1.5 times the delay retry, total retry times 4
@retryable (value = {Exception. Class}, maxAttempts = 4, backoff = @backoff (delay = 2000L, Multiplier = 1.5))
Copy the code
  1. The listening method is configured in the configuration class
/** * annotation call */
@Bean
public RetryListener retryListener(a) {
    return new RetryListener() {
        @Override
        public T, E extends Throwable boolean open(RetryContext context, RetryCallbackT, E callback) {
            System.out.println("open context = " + context + ", callback = " + callback);
            // Return true to continue with subsequent calls
            return true;
        }

        @Override
        public T, E extends Throwable void close(RetryContext context, RetryCallback
       
         callback, Throwable throwable)
       , {
            System.out.println("close context = " + context + ", callback = " + callback);
        }
        @Override
        public T, E extends Throwable void onError(RetryContext context, RetryCallback
       
         callback, Throwable throwable)
       , {
            System.out.println("onError context = " + context + ", callback = "+ callback); }}; }Copy the code
  1. Call the service
@RestController
public class SpringRetryController {
    @Resource
    private PlatformClassService platformClassService;
    
    @RequestMapping("/retryPlatformCall")
    public Object retryPlatformCall(a) {
        try {
            platformClassService.call();
        } catch (Exception e) {
            return "Failed attempt to invoke";
        }
        return "retryPlatformCall"; }}Copy the code
  1. The results

Search
About
mo4tech.com (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.