Spring Boot @Retryable

Yeomso(BE)·2023년 5월 8일
0

회사에서 @Retryable 이라는 어노테이션을 쓰는 기회가 생겨 내가 공부한 내용에 대해서 정리를 하려고 한다.

사건의 시작은 특정 작업을 하는 schedule이 정상적으로 처리가 되야 하는데, restTemplate를 쓰다보니 예상치 못한 에러가 발생을 했다.

  1. 네트워크 장애
  2. 연동 서버 장애
  3. 기타 등등

여러가지 장애가 발생하는 것 같았다.

해당 장애를 해결하고자 재처리를 시도하면 좋을거 같아 이것저것 찾아보던 와중 @Retryable이라는 기능을 발견하게 되었다.

업무에서는 하라는 대로 하니깐 잘 처리가 되서 매우 기뻤지만, 그러면 나의 실력이 안되니 집에와서 따로 정리하는 시간을 가지기로 했다.

내가 적용한 내용은 아주 간단했다. 특정 에러가 발생을 하면, 3회 재처리를 하도록 만들었다.
간격은 1초로 설정을 했다.

@Retryable(maxAttempts = 3, backoff = Backoff(delay = 1000), value = [IOException::class])

@Retryable 어노테이션은 여러 가지 속성을 제공합니다. 주요 속성은 다음과 같습니다.

  • value: RetryCallback과 RecoverCallback을 명시적으로 설정하지 않고, 메서드 시그니처로부터 추론할 수 있도록 합니다. 기본적으로 빈 RetryCallback과 RecoverCallback을 생성합니다.

  • include: Retry할 예외 클래스나 그 클래스 이름을 포함한 문자열 패턴입니다.

  • exclude: Retry하지 않을 예외 클래스나 그 클래스 이름을 포함한 문자열 패턴입니다.

  • maxAttempts: Retry 시도 횟수의 상한을 정합니다. 기본값은 3입니다.

  • backoff: Retry 시도 간격을 설정합니다. 기본값은 @Backoff(maxAttempts=3, delay=1000, multiplier=1.0)입니다. maxAttempts, delay, multiplier 등을 조절할 수 있습니다.

@Backoff 어노테이션은 Retry 시도 간격을 지정하는 데 사용됩니다. delay, multiplier, maxDelay 등의 속성이 있습니다.

  • delay: 첫 번째 Retry 시도와 두 번째 Retry 시도 사이의 시간 간격입니다. 기본값은 1000ms입니다.

  • multiplier: Retry 시도 간격을 계산하는 데 사용할 곱셈 계수입니다. 기본값은 1.0입니다.

  • maxDelay: Retry 시도 간격의 상한입니다. 기본값은 Long.MAX_VALUE입니다.

나는 이러한 속성도 배웠고, 먼가 고정적으로 retry를 하고 싶어서 더 찾아본 결과 Bean으로 templete을 만드는 방법을 찾아냈다.

@Configuration
@EnableRetry
class RetryConfig {

    @Bean
    fun retryTemplate(): RetryTemplate {
        val retryTemplate = RetryTemplate()
        val retryPolicy = SimpleRetryPolicy(3) // 재시도 정책
        val backOffPolicy = ExponentialBackOffPolicy() // 재시도 간격을 지수적으로 증가
        retryTemplate.setRetryPolicy(retryPolicy)
        retryTemplate.setBackOffPolicy(backOffPolicy)
        return retryTemplate
    }

    @Bean
    fun retryInterceptor(): RetryOperationsInterceptor {
        val interceptor = RetryOperationsInterceptor()
        interceptor.setRetryOperations(retryTemplate()) // retryTemplate()으로 RetryOperationsInterceptor 빈 생성
        return interceptor
    }
}
  • @EnableRetry 어노테이션은 Spring Retry를 사용하기 위해 설정해야 하는 어노테이션입니다. 이 어노테이션이 붙은 클래스에서 Retry 기능을 사용할 수 있습니다.

  • RetryTemplate은 Spring Retry에서 제공하는 핵심 클래스 중 하나로, 재시도 로직을 구현할 수 있습니다.

  • SimpleRetryPolicy는 최대 재시도 횟수를 설정

  • ExponentialBackOffPolicy는 재시도 간격을 지수적으로 증가시키는 방식으로 설정

  • RetryOperationsInterceptor는 RetryTemplate 객체를 받아서 Retry 기능을 적용해 주는 인터셉터입니다.

  • RetryInterceptor는 @Retryable 어노테이션이 붙은 메소드를 실행할 때 RetryTemplate을 사용하여 재시도 로직을 수행합니다.

@Service
class ReTryService {

    @Retryable(interceptor = "retryInterceptor", value = [IOException::class])
    fun retryTest() {

        println("test try")
        throw IOException()

    }

    @Retryable(maxAttempts = 2, backoff = Backoff(delay = 1000), value = [IOException::class])
    fun retryTest2() {

        println("test try")
        throw IOException()

    }
}

간단하게 잘 재시도 되는지 테스트를 해보았고, interceptor를 이용한 templete 방식과 기본적으로 제공하는 방식 2가지를 테스트 해보았다.

@SpringBootTest
class ReTryServiceTest {
    @Autowired
    lateinit var retryTemplate: RetryTemplate

    @Autowired
    lateinit var reTryService: ReTryService

    @Test
    fun testRetry() {
        assertThrows<IOException> {
            reTryService.retryTest()
        }
    }

    @Test
    fun testRetry2() {

        assertThrows<IOException> {
            reTryService.retryTest2()
        }

    }

}

심플하게 JUnit으로 내가 만든 코드를 테스트를 진행했고, testRetry는 3번의 test try 문구가 testRetry2()는 2번의 test try 문구가 찍히는 것을 확인했다.

이로써 오늘도 재미있는 기능을 알아갈 수 있어서 좋았다.

상세 코드는 아래 주소를 참고하면 됩니다.
https://github.com/shyeom1023/blog/blob/develop/demo/src/main/kotlin/com/example/demo/infra/RetryConfig.kt

참고한 블로그
https://yeon-kr.tistory.com/m/213

상세 내용(chat gpt)
https://chat.openai.com/

profile
나 혼자만 개발중

0개의 댓글