[Spring] RestTemplate의 Connection Timeout 설정과 에러 패턴
ㅁ 들어가며
ㅇ 회사에서 외부API의 통신에서 에러가 발생하여 그 원인을 분석하였다.
ㅇ 외부 연동된 API는 처리하는데 1.7초, 내부적으로 Connection Timeout 설정이 1.5초로 되어 있었다.
ㅇ 이번 글에서는 Connection Timeout 설정 방법과 에러 패턴, 최적의 Timeout 설정, 에러 처리 및 로깅 방법에 대해서 정리해 보았다.
ㅁ Connection Timeout 설정 방법
Spring RestTemplate에서 connection timeout을 설정하는 방법은 크게 두 가지가 있다.
1. HttpComponentsClientHttpRequestFactory 사용
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 5초
factory.setReadTimeout(5000); // 5초
RestTemplate restTemplate = new RestTemplate(factory);
이 방법은 Apache HttpComponents 라이브러리를 사용하여 connection timeout과 read timeout을 모두 설정할 수 있다.
2. RestTemplateBuilder 사용 (Spring Boot)
Spring Boot 환경에서는 RestTemplateBuilder를 사용하여 더 간단하게 설정할 수 있다.
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
}
ㅁ Connection Timeout 에러 패턴
Connection timeout이 발생하면 일반적으로 다음과 같은 에러 패턴이 나타난다.
ㅇ SocketTimeoutException
java.net.SocketTimeoutException: 이 예외는 connection timeout 또는 read timeout이 발생했을 때 던져진다.
java.net.SocketTimeoutException: Connect timed out
ㅇ ResourceAccessException
org.springframework.web.client.ResourceAccessException: RestTemplate은 일반적으로 SocketTimeoutException을 ResourceAccessException으로 감싸서 던진다.
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://example.com": Connect timed out; nested exception is java.net.SocketTimeoutException: Connect timed out |
ㅇ ConnectException
java.net.ConnectException: 때때로 connection timeout은 ConnectException으로 나타날 수 있다.
java.net.ConnectException: Connection timed out: connect
ㅁ 최적의 Timeout 설정
적절한 timeout 값을 설정하는 것은 매우 중요하다. 너무 짧게 설정하면 정상적인 요청도 timeout으로 처리될 수 있고, 너무 길게 설정하면 리소스 낭비가 발생할 수 있다. 일반적으로 다음과 같은 기준을 고려할 수 있다.
ㅇ 네트워크 지연: 외부 API와의 통신 시 네트워크 지연을 고려해야 한다. 일반적으로 수 초 정도의 값이 적당하다.
ㅇ API 응답 시간: 호출하는 API의 평균 응답 시간을 파악하고, 이를 기반으로 timeout을 설정한다.
ㅇ 재시도 전략: timeout 발생 시 재시도 로직을 구현한다면, 첫 번째 timeout은 짧게 설정하고 재시도 시 점진적으로 늘릴 수 있다.
ㅁ 에러 처리 및 로깅
Connection timeout 에러를 효과적으로 처리하기 위해서는 적절한 예외 처리와 로깅이 필요하다.
try {
ResponseEntity<String> response = restTemplate.getForEntity("http://example.com", String.class);
// 응답 처리
} catch (ResourceAccessException e) {
if (e.getCause() instanceof SocketTimeoutException) {
log.error("Connection timeout occurred: {}", e.getMessage());
// timeout 처리 로직
} else {
log.error("Other I/O error occurred: {}", e.getMessage());
// 다른 I/O 에러 처리
}
} catch (HttpClientErrorException e) {
log.error("HTTP client error: {}", e.getMessage());
// HTTP 클라이언트 에러 처리
} catch (HttpServerErrorException e) {
log.error("HTTP server error: {}", e.getMessage());
// HTTP 서버 에러 처리
}
이러한 에러 처리 로직을 통해 timeout 발생 시 적절한 대응을 할 수 있다. 예를 들어, 재시도 로직을 구현하거나 대체 API를 호출하는 등의 방법을 사용할 수 있다.
ㅁ 마무리
Spring RestTemplate에서 connection timeout을 적절히 설정하는 것은 애플리케이션의 안정성과 성능을 위해 매우 중요하다. HttpComponentsClientHttpRequestFactory나 RestTemplateBuilder를 사용하여 쉽게 timeout을 설정할 수 있으며, 이를 통해 SocketTimeoutException이나 ResourceAccessException과 같은 에러를 방지할 수 있다.
timeout 설정은 단순히 에러를 방지하는 것을 넘어 전체 시스템의 안정성과 확장성을 높인다. 또한, 적절한 예외 처리와 로깅을 통해 timeout 발생 시 효과적으로 대응할 수 있어, 최적의 timeout 설정을 유지하는 것이 중요하다.
ㅁ 함께 보면 좋은 사이트
ㅇ [Spring] RestTemplate은 Thread Safe할까? / RestTemplate 타임아웃(Timeout), 재시도(Retry), 로깅(Logging) 설정하기
ㅇ [Spring] RestTemplate 타임아웃(Timeout), 재시도(Retry), 로깅(Logging) 등 설정하기