[Spring] Spring Retry

soohee·2023년 4월 16일
0

Spring

목록 보기
12/13
post-thumbnail

Spring Batch에 대해 알아보다가, 실패한 동작을 자동으로 다시 호출해서 이어서 진행해주는 기능이 너무 좋아보였다. 그러다가 Spring Framework에서는 그 기능만 사용할 수 없을까? 하여 찾아보다가 재시도 패턴을 다루는 Spring Retry 라이브러리를 발견했다.

Spring Retry 란?

실패할 경우 그 동작을 자동으로 다시 호출하는 기능이 담긴 라이브러리로, 버전 2.2.0부터 Spring Batch에서 제거되어 사용되고 있다. Spring Batch에서 분리된 재시도 패턴은 여전히 Spring Retry 라이브러리를 통해 사용중이다.

Spring Retry를 사용하는 방법

Spring Retry를 사용하는 방법에는 2가지가 존재한다.

1. 프로그래밍 방식 (Retry Template 활용)

RetryOperations

Spring Framework에서는 Retry를 제공하는 RetryOperations 인터페이스를 제공하고, 그 구현체로 RetryTemplate를 제공한다.

RetryCallback

excute 메서드의 매개변수로 들어있는 RetryCallback 인터페이스에서는 doWithRetry라는 메서드가 존재하는데, 이곳에서 재시도 할 비즈니스 로직이 들어가게 된다.

콜백이 실패하면 (Exception이 발생하면) 재시도 정책에 따라서 특정 횟수 혹은 특정 시간동안 재시도를 할 것이다. RetryOperations에는 재시도가 모두 실패했을때, 실패에 대한 처리하는 콜백 메소드를 인자로 받는 execute 메소드를 제공한다.

RetryTemplate를 활용해, Catch 할 Exceptions, Retry Period, Retry Max Count 등을 설정하여, 재시도 패턴을 구현할 수 있다.

RecoveryCallback

모든 재시도가 실패하고 더이상 재시도할 수 없는 경우, RecoveryCallback 메소드를 호출한다. RecoveryCallback의 recover 메소드에서는 재시도가 전부 실패한 경우에 대한 대체 로직을 수행한다.

Stateless Retry

RetryTemplate는 성공하거나 혹은 실패할 때까지 계속해서 재시도할 수 있다. RetryCallback메소드 파라미터인 RetryContext에서는 상태를 포함하고 있다. 그리고 그 상태를 가지고 재시도를 할지 혹은 중단할지 여부를 결정한다. 이 상태는 보통의 경우 전역으로 저장할 필요가 없다. 이러한 재시도를 stateless retry라 한다. stateless 재시도에서는 콜백이 항상 동일한 스레드에서 실행된다.

2. 선언적 방식 (Retry Annotation 활용)

두번째 방식은 Retryable Annotation을 통해 재시도를 수행하도록 구현하는 것이다.
참고로 선언적 방식의 Retry 는 Spring AOP 를 사용하기 때문에 Aspect depenency 까지 추가해주어야 한다.

Retry 설정 켜주기

먼저 build.gradle에 dependency를 추가해주자

main function에 Retry 설정을 켜주는 @EnableRetry Annotation을 추가하자.

@Retryable

재시도하길 원하는 service 로직에 @Retryable Annotation을 추가하자.

  • value : 예외 대상
  • maxAttempts : 재시도 횟수
  • backoff : 재시도 사이의 시간 간격

@Recover

@Recover는 @Retryable 세팅에 의해 재시도를 했음에도 불구하고 실패했을 경우 후처리를 담당한다.

특정 Exception 에 대한 Retry 를 수행해서 최종적으로 Exception 이 발생하면, 특정 동작을 수행하게 할 수 있다. 주의할 점은 처음 exception 인자를 제외한 나머지 입력/출력이 타겟 메소드와 동일해야 한다는 점이다.

Spring Retry를 사용하는 이유

이는 일시적인 네트워크 결함과 같이 오류가 일시적 일 수 있는 경우에 유용하다.
1번의 네트워크 호출 실패로 서비스의 비지니스 로직을 모두 실패처리하거나 fallback 처리하는 것은 몇 번 다시 호출하는 것보다 큰 리소스 낭비가 될 수 있기 때문이다.

그러나, 대부분의 네트워크 오류 상황은 특정 시간동안 네트워크 이슈가 지속되는 경우가 많기 때문에 3회 재시도를 하더라도 모두 실패로 끝날 가능성이 높아져 오히려,
네트워크에 더 부담을 줄 가능성이 크다. 예를들어 트래픽이 몰려서 요청 자체가 지연되고 있는데 모든 클라이언트가 재시도를 연속으로 시도한다고 생각해보자. 네트워크 트래픽이 최대 3배 더 증가할 것이다.

뭔가.. 좀 똑똑하게 Retry를 사용해야할 듯 싶다.

출처
https://backtony.github.io/spring/2022-06-05-spring-retry-1/

profile
🐻‍❄️

2개의 댓글

comment-user-thumbnail
2023년 4월 17일

Spring Retry의 존재를 처음 알았어요! 유용하네용

1개의 답글