Spring
Retry
Bong Gu
2022. 1. 8. 06:21
728x90
Spring-retry
- 실패한 동작을 자동으로 다시 호출하는 기능을 제공한다.
- 일시적인 네트워크 결함과 같이 오류가 일시적 일 수 있는 경우에 유용하다.
의존성
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
- 또한 Spring AOP 의존성도 필요하지만
spring-boot-start-data-jpa
에 들어있다.<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.8.RELEASE</version> </dependency>
Enabling Spring Retry
@EnableRetry
@SpringBootApplication
public class RetryApplication {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Annotation
@Retryable
@Service public class MyService { static int retryCount = 0; @Retryable( value = {SQLException.class}, maxAttempts = 2, backoff = @Backoff(delay = 2000)) int countContents() throws SQLException { retryCount++; System.out.println("retryCount " + retryCount); if (retryCount == 2) { return 100; } else { throw new SQLException(); } } }
- 재시도할 메소드 호출을 작성할 수 있다.
- value : SQLException 발생시키는 경우 재시도
- maxAttempts : 최대 2번의 재시도
- backoff : 2000 millisecond의 텀을 두고 시도
- 아무 속성 없이 사용할 경우, 예외가 발생하면 기본적으로 1초의 지연으로 최대 3번 재시도한다.
@Recover
@Retryable( value = {SQLIntegrityConstraintViolationException.class}, maxAttempts = 4, backoff = @Backoff(delay = 2000)) int deleteContents(String sql) throws SQLIntegrityConstraintViolationException { retryCount3++; System.out.println("retryCount " + retryCount3); throw new SQLIntegrityConstraintViolationException(); } @Recover public int recover(SQLIntegrityConstraintViolationException e, String sql) { System.out.println("Recover called : message=" + e.getMessage() + ", sql=" + sql); return 50; }
@Retryable
메소드가 지정된 예외로 실패할 때, 별도의 복구 메소드를 정의하는데 사용된다.- maxAttempt만큼 재시도 후 복구가 안되었을 경우
recover()
메소드가 최종 호출됩니다.
RetryTemplate
execute() 메소드를 제공하는 RetryOperations 인터페이스를 제공
public interface RetryOperation { <T> T execute(RetryCallback<T> retryCallback) throws Exception; ... }
- RetryCallback
public interface RetryCallback<T> { T doWithRetry(RetryContext context) throws Throwable; }
- RetryCallback
RetryTemplate는 RetryOperations의 구현체
적용
bean 등록
@EnableRetry @SpringBootApplication public class RetryApplication { public static void main(String[] args) { SpringApplication.run(RetryApplication.class, args); } @Bean public RetryTemplate retryTemplate() { RetryTemplate retryTemplate = new RetryTemplate(); FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); fixedBackOffPolicy.setBackOffPeriod(2000l); retryTemplate.setBackOffPolicy(fixedBackOffPolicy); SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(); retryPolicy.setMaxAttempts(2); retryTemplate.setRetryPolicy(retryPolicy); retryTemplate.registerListener(new DefaultListenerSupport()); return retryTemplate; } }
Listener
public class DefaultListenerSupport extends RetryListenerSupport { @Override public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { logger.info("onClose); // 로직 super.close(context, callback, throwable); } @Override public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { logger.info("onError"); // 로직 super.onError(context, callback, throwable); } @Override public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { logger.info("onOpen); // 로직 return super.open(context, callback); } }
- open, close : 전체 재시도 전후
- onError : 개발 재시도 시
사용
// callback 방식 retryTemplate.execute(new RetryCallback<Integer, RuntimeException>() { @Override public Integer doWithRetry(RetryContext context) { return myService.countContentsForRetryTemplate(); } }); // lambda 방식 retryTemplate.execute(context -> myService.countContentsForRetryTemplate());
참고
728x90