How-To
Add spring-retry in your pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>test</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>test</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Create email service
package com.example.service; import com.example.rest.EmailResource; import lombok.extern.slf4j.Slf4j; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Recover; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; @Slf4j @Service public class EmailService { private int counter = 0; /** * 最多 retry 5 次,每次 retry 間隔 5 秒鐘 * * @param param */ @Retryable(maxAttempts = 5, backoff = @Backoff(delay = 5000)) public void sendMailWithRetry(EmailResource.EmailParam param) { counter++; log.debug("Failed to send mail. Retried " + counter + " times"); throw new IllegalArgumentException("some error happened"); } /** * 當 retry 5 次全部失敗,則到 recover method,印出錯誤訊息 * * @param throwable * @param param */ @Recover public void recover(Throwable throwable, EmailResource.EmailParam param) { String errorMsg = "fail to retry 5 times, param = %s, error message : %s"; throw new IllegalArgumentException(String.format(errorMsg, param, throwable.getMessage())); } }
Create email resource class
package com.example.rest; import com.example.service.EmailService; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController @RequestMapping(value = "/email") public class EmailResource { @Autowired private EmailService emailService; @PostMapping(value = "/send") public void sendMail(@RequestBody EmailParam param) { emailService.sendMailWithRetry(param); } @Data public static class EmailParam { private String to; private String subject; private String content; } }
Enable spring retry function
package com.example.test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.retry.annotation.EnableRetry; // add @EnableRetry annotation to enable spring retry function @EnableRetry @SpringBootApplication @ComponentScan(basePackages = "com.example") public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } }
Do test and check result
2018-11-28 09:55:32.135 DEBUG 9804 --- [nio-8080-exec-1] com.example.service.EmailService : Failed to send mail. Retried 1 times 2018-11-28 09:55:37.136 DEBUG 9804 --- [nio-8080-exec-1] com.example.service.EmailService : Failed to send mail. Retried 2 times 2018-11-28 09:55:42.138 DEBUG 9804 --- [nio-8080-exec-1] com.example.service.EmailService : Failed to send mail. Retried 3 times 2018-11-28 09:55:47.138 DEBUG 9804 --- [nio-8080-exec-1] com.example.service.EmailService : Failed to send mail. Retried 4 times 2018-11-28 09:55:52.139 DEBUG 9804 --- [nio-8080-exec-1] com.example.service.EmailService : Failed to send mail. Retried 5 times 2018-11-28 09:55:52.215 ERROR 9804 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: fail to retry 5 times, param = EmailResource.EmailParam(to=junyuo@gmail.com, subject=email subject, content=email content), error message : some error happened] with root cause java.lang.IllegalArgumentException: fail to retry 5 times, param = EmailResource.EmailParam(to=junyuo@gmail.com, subject=email subject, content=email content), error message : some error happened at com.example.service.EmailService.recover(EmailService.java:37) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]