이번 포스팅에선 Spring에서 재시도할 때 사용하는 어노테이션 @Retryable, @Recover에 대해 알아보겠다.
@Retryable이란?
Bean의 메소드 실행 도중 exception이 발생한 경우 재시도를 할 수 있게 해주는 어노테이션
@Retryable 사용 방법
1. spring-retry 의존성 추가
implementation("org.springframework.retry:spring-retry")
2. Spring Application에 @EnableRetry 추가
@EnableRetry
@SpringBootApplication
class SpringApplication
3. 재시도할 메서드에 @Retryable 추가
@Service
class RetryableService {
@Retryable
fun retryableMethod() {
...
}
}
@Retryable 옵션
maxAttempts, maxAttemtsExpression(SpEL 형식)
최대 재시도 횟수다. 기본 값은 3이다.
@Service
class RetryableService {
@Retryable(maxAttempts = 4)
fun retryableMethod() {
...
}
}
recover
maxAttempts까지 재시도를 했는데 성공을 못 한 경우, 호출할 메소드를 정의하는 거다.
recover에 사용할 메소드는 반드시 @Recover이 있어야 한다.
@Service
class RetryableService {
@Retryable(recover = "recoverMethod2")
fun retryableMethod() {
...
}
@Recover
fun recoverMethod() {
...
}
@Recover
fun recoverMethod2() {
...
}
@Recover
fun recoverMethod3() {
...
}
}
@Recover가 하나만 있는 경우엔 recover를 생략할 수 있다.
@Service
class RetryableService {
@Retryable
fun retryableMethod() {
...
}
@Recover
fun recoverMethod() {
...
}
}
@Recover가 2개 이상 있는데 recover를 안 쓰면 맨 아래에 있는 메소드가 사용된다.
@Service
class RetryableService {
@Retryable
fun retryableMethod() {
...
}
@Recover
fun recoverMethod() {
...
}
@Recover
fun recoverMethod2() {
...
}
@Recover << 맨 마지막 거 실행
fun recoverMethod3() {
...
}
}
존재하지 않는 recover를 사용한 경우
@Service
class RetryableService {
@Retryable(recover = "recoverMethod")
fun retryableMethod() {
...
}
}
maxAttempts만큼 실행이 추가로 되고 "org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method' 에러가 발생한다.
backoff
재시도 시간을 조절할 때 사용한다.
- delay: 지연 시간 (ms)
- maxDelay: 최대 지연 시간
- multiplier: 재시도마다 delay * multiplier만큼 지연 시간 추가
@Service
class RetryableService {
@Retryable(
recover = "recoverMethod",
backoff = Backoff(
delay = 1000,
maxDelay = 3000,
multiplier = 2.0
)
)
fun retryableMethod() {
...
}
}
- random: 지연 시간을 랜덤으로 설정
@Service
class RetryableService {
@Retryable(
recover = "recoverMethod",
backoff = Backoff(
random = true,
maxDelay = 1000
)
)
fun retryableMethod() {
...
}
}
- delayExpression, maxDelayExpression, multiplierExpression, randomExpression: 각 옵션을 SpEL로 표현 가능
// 이전 재시도 간격의 두 배를 사용하여 백오프 간격을 설정
multiplierExpression = "#lastInterval * 2"
// 현재 재시도 횟수에 따라 지수적으로 증가하는 값을 사용하여 백오프 간격을 설정
multiplierExpression = "T(java.lang.Math).pow(2, #currentRetryContext.retryCount) * 1000
include (= value, retryFor), exceptionExpression(SpEL 형식)
retryable 대상 Exception 타입 설정할 때 사용
@Service
class RetryableService {
@Retryable(include = [ReadTimeoutException::class])
fun retryableMethod() {
...
}
}
exclude (= noRetryFor)
retryable 대상 제외 Exception 타입 설정할 때 사용
@Service
class RetryableService {
@Retryable(exclude = [ReadTimeoutException::class])
fun retryableMethod() {
...
}
}
notRecoverable
recover 대상 제외 Exception 타입 설정할 때 사용
@Service
class RetryableService {
@Retryable(notRecoverable = [ReadTimeoutException::class])
fun retryableMethod() {
...
}
}
이외에 label, stateful, interceptor, listeners 가 있는데 정확한 사용처를 모르겠어서 나중에 알게되면 추가하겠다.
현재 Retry 횟수 정보를 알고 싶다면?
RetrySynchronizationManager.getContext()로 RetryContext를 꺼내서 사용하면 된다.
RetrySynchronizationManager.getContext()?.retryCount
'Spring' 카테고리의 다른 글
[Spring] Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation '=', 'UNION' (1) | 2024.03.30 |
---|---|
[Spring] Spring Boot + Kotlin + MyBatis 프로젝트 설정 방법 (3) | 2024.03.26 |
[Spring] Kotest 병렬 테스트 설정 방법 (23) | 2023.12.31 |
[Spring] Gradle Test events were not received 해결 방법 (21) | 2023.12.28 |
[Spring] Kotest와 Mockk를 사용할 때 주의할 점 (26) | 2023.12.26 |
댓글