Spring Retry
업데이트:
Spring Retry1Permalink
- Spring Project를 구성하다보면 비즈니스 로직이 정상적으로 이루어지지 않는 경우에 대한 재시도 및 오류 처리에 대한 로직을 구현할 필요가 있다.
- Spring Retry는 Spring Batch Project에서 파생되어, 현재는 분리되어 단독으로 발전해가는 프로젝트이다.
DependencyPermalink
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>2.0.11</version>
</dependency>
implementation 'org.springframework.retry:spring-retry:2.0.11'
- 일반적으로 “spring-retry”에 대한 maven dependency로 추가 혹은 gradle implementation하여 사용할 수 있다.
- 최신 Spring Boot 프로젝트에서는 버전을 명시하지 않으면, 해당 parents에 정의된 버전으로 사용할 수 있다.
@Retryable & @RecoverPermalink
@Service
public interface SqlService {
@Retryable(retryFor = SQLException.class, maxAttempts = 3, backoff = @Backoff(delay = 100))
void execute(String sql);
@Recover
void recover(SQLException e, String sql);
}
- @Retryable은 특정 비즈니스 로직 내 오류가 발생했을 때, 해당 메서드의 재시도를 수행할 수 있도록 정의하는 어노테이션이다.
- retryFor는 특정 오류 상황이 발생하였을 때 재 시도 하도록 정의하는 속성이다.
- maxAttempts는 retryFor 내 정의된 오류가 발생했을 때 최대 반복 횟수를 정의하는 속성이다.
- backoff는 재 시도 수행 간 지연 시간을 정의하는 속성이다.
- @Recover는 @Retryable 어노테이션을 정의한 메서드가 실패하였을 경우, 최종 오류에 대한 제어 및 복구를 위해 제공되는 어노테이션이다.
public interface FileService {
@Retryable(retryFor = IOException.class, maxAttemptsExpression = "${retry.maxAttempts}", backoff = @Backoff(delayExpression = "${retry.maxDelay}"))
void write(String path, String body);
}
- maxAttempts와 backoff를 application.yml 혹은 application.properties 내 정의하여 코드를 수정하지 않아도 동적으로 변경 가능하도록 하는 maxAttemptsExpression 속성과 delayExpression 속성 또한 제공된다.
RetryTemplatePermalink
@Configuration
public class RetryTemplateConfig {
@Bean
RetryTemplate retryTemplate(
@Value("${retry.maxAttempts}") int maxAttempts,
@Value("${retry.maxDelay}") long backoff
) {
RetryTemplate retryTemplate = new RetryTemplate();
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(backoff);
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(maxAttempts);
retryTemplate.setRetryPolicy(retryPolicy);
retryTemplate.registerListener(new CustomRetryListener());
return retryTemplate;
}
}
- @Retryable 어노테이션 뿐 아니라, RetryTemplate을 통해서 비즈니스 수행을 원하는 정책에 따라 재시도할 수 있다.
RetryListenerPermalink
public class CustomRetryListener implements RetryListener {
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
// Something to close.
}
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
// Something on error.
}
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
// Something to open.
return true;
}
}
- Retry 시도에 따라 각 상황 별 추가 로깅, 비즈니스 로직들을 추가할 수 있다.
- @Retryable 어노테이션과 RetryTemplate 모두 해당 Listener를 주입하여 활용할 수 있다.
ConclusionPermalink
- 장애 상황에 따른 복구와 대처 방안은 항상 최악의 상황을 대비할 수 있는 서비스 안정성에 기여가 된다.
- 만일 API 서비스가 Cloud 혹은 On-Premise 환경 내 API 서비스만 존재한다고 가정하면 한 환경의 장애로 서비스가 단절될 수 있지만, 이렇게 Circuit Breaker 역할을 수행할 수 있는 기능들이 존재하면 RPO(Recovery Point Objective)와 RTO(Recovery Time Objective)를 현저히 줄일 수 있을 것이다.
- 안정적인 서비스는 사용자의 편의성과 신뢰도를 바탕으로, 더욱 발전하는 서비스가 될 기회를 맞이할 것이다.
ReferencePermalink
※ Sample Code는 여기에서 확인 가능합니다.
댓글남기기