์กฐ๊ธ ๋ ๊ด์ฐฎ์ Rest Template 1๋ถ - Retryable
์น ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค๋ฉด์ ๊ผญ ํ๋ฒ ์ฏค ๋ง๋๊ฒ ๋๋ “RestTemplate”. ์ ๊ทผ ๊ฐ๋ฅํ ์ธ๋ถ HTTP URL(๋ณดํต API)์ ํธ์ถํ๋ ๋ฐฉ๋ฒ์ค์ ํ๋๋ก springframework ์์ ์ ๊ณตํด์ฃผ๋ ๋ชจ๋์ด๋ค. ํนํ ํฐ ํ๋ฉ์ด๋ฆฌ๋ก ๊ด๋ฆฌ๋๋ Monolithic Architecture ์์ ์์ฒญ์ ํ๊ณ (client) ์๋ต์ ์ฃผ๋(server) ์ฆ, Endpoint๊ฐ ์์ ๋จ์๋ก ๋ถ๋ฆฌ๋๋ Microservice Architecture ๋ก ๋ฐ๋๋ฉด์ ๊ฐ ์๋น์ค๊ฐ ํธ์ถ๋ฐฉ์์ด HTTP ์ผ ๊ฒฝ์ฐ ์์ฃผ ์ฌ์ฉ๋๊ณค ํ๋ ๊ฒ ๊ฐ๋ค. (webClient ๋ฑ ๋ค๋ฅธ ์ฌ๋ฌ ํธ์ถ ๋ฐฉ๋ฒ๋ค์ด ์๋ค.) ๋ง์ฝ, ์์ฒญ์ ํ๋ ํด๋ผ์ด์ธํธ ์ ์ฅ์์ ์๋ต์ ์ฃผ๋ ์๋ฒ์ ์ํ๊ฐ ๋ถ์์ ํ๋ค๊ณ ๊ฐ์ ํ์๋, ์ด๋ค์์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ ๊น? ์์ปจ๋, ์์ฒญ 10๋ฒ์ ํ๋ฒ์ ์ด๋ ํ ์ด์๋ก ์๋ต์ด ์ง์ฐ๋๊ฑฐ๋ ์๋ฒ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๊ณ ํ๋ฉด ํด๋ผ์ด์ธํธ๋ฅผ ์ฌ์ฉํ๋ ์ฌ์ฉ์ ์ ์ฅ์์๋ ๊ฐํ์ ์ธ ์ค๋ฅ์๋ต์ ๋ต๋ตํจ์ ํธ์ํ ์๋ ์๋ค. ๊ทธ๋ผ ์ ์ ๋์ ๊ฐ๊ณ ์๊ฐํด๋ณด์. ๊ฐ๋ณ๊ฒ ์๊ฐํ๋ฉด ์๋์ฒ๋ผ ์์ฃผ ๊ฐ๋จํ๊ฒ “์์ธ์ฒ๋ฆฌ"๋ฅผ ์ด์ฉํ ์๋ ์๋ค.
try {
// http call
} catch (Exception e){
// ์๋ฒ์๋ฌ๊ฐ ์๋ ์ฝ์๋ ์๋ฌ์๋ต์ ๋ฆฌํด
}
ํ์ง๋ง ์ด๊ฒ๋ ์ ๋ต์ด ์๋์ ์๋๊ฒ, “๊ฐํ์ ์ธ ์ค๋ฅ"๋ก ์ธํด ์ฌ์ฉ์๋ ์ค๋ฅํ๋ฉด์ ๋ด์ผํ๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ์ ๋ํ ์ ๋ขฐ๋ฅผ ์ ๋ฒ๋ฆด ์๋ฐ์ ์๋ค. ๊ทธ๋ผ ์ด๋ป๊ฒ ํด์ผํ ๊น? ์ฌ๋ฌ๊ฐ์ง ํด๊ฒฐ๋ฐฉ๋ฒ์ด ์๊ฒ ์ง๋ง ๊ฐ๋จํ๋ฉด์๋ ๊ฐ๋ ฅํ๋ค๊ณ ์๊ฐ๋๋ ๋ฐฉ๋ฒ์ด ๋ฐ๋ก “์ฌ์๋” ๋ผ๊ณ ์๊ฐํ๋ค. ํด๋ผ์ด์ธํธ๋ฅผ ์ฌ์ฉํ๋ ์ฌ์ฉ์๊ฐ ๋์น ๋ชป์ฑ๋งํผ ๋น ๋ฅด๊ฒ ์ฌ์๋๋ฅผ ํ๋ค๋ฉด ์๋ฌ๊ฐ ๋๋ ๋ค์ํ๋ฒ ํธ์ถํด์ ์ฑ๊ณตํ ์ ์๋ ๊ฐ๋ฅ์ฑ์ด ๋๊ธฐ ๋๋ฌธ์ด๋ค. (๊ทธ์น๋ง ๊ทผ๋ณธ์ ์ธ ์์ธ์ ํด๊ฒฐํด์ผ…)

์ถ์ฒ : http://www.segye.com/newsView/20200302504384
์ด๋ฒ ํฌ์คํ ์์๋ RestTemplate ๋ฅผ ์ด์ฉํ ๋ “์ฌ์๋” ํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด๊ณ ์ ํ๋ค. ์์ฃผ ๊ฐ๋จํ ์ง ๋ชจ๋ฅด์ง๋ง ๋ ธ๋ ฅ์ ๋นํด ํจ๊ณผ๊ฐ ์๋นํ๋ค๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ์ ๋ฆฌํด ๋๊ณ ์ถ์๋ค.
Spring Retry
๊ณต์ Github์ ์๊ฐ๋ฅผ ๋น๋ฆฌ์๋ฉด, Spring ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ํ ์ฌ์๋ ์ง์์ ์ ๊ณตํ๋ค๊ณ ํ๋ค. ์์์ ์ด์ผ๊ธฐ ํ๋ “RestTemplate"๊ณผ๋ ์ฌ์ค ๋ฌด๊ดํ๊ณ , ์ด๋ฅผ ํ์ฉํด์ ์ฌ์๋ ํ๋ “RetryRestTemplate"๋ฅผ ๊ตฌํํด๋ณด๋ ค ํ๋๊ฒ์ด๋ค. ์ฐ์ ์ด “Spring-Retry"์ ์์ ๋ฅผ ๋ณด๋ฉด ์์ฃผ ์ฌํํ๊ฒ ์ฌ์ฉํ ์ ์๋ค. ์ฐ์ pom์ ๊ตฌํ์ ํ์ํ dependency ๋ฅผ ์ถ๊ฐํ๊ณ ์๋ ์ฝ๋๋ฅผ ๋ณด์.
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Configuration
@EnableRetry // 1
public class Application {
@Bean
public Service service() {
return new Service();
}
}
@Service
class Service {
@Retryable(RemoteAccessException.class) // 2
public void service() {
// ... do something
}
@Recover // 3
public void recover(RemoteAccessException e) {
// ... panic
}
}
- @EnableRetry ์ด๋ ธํ ์ด์ ์ @Configuration์ ์ง์ ํ ํด๋์ค ์ค ํ๋์ ์ถ๊ฐํ๋ค.
- ์ฌ์๋ ํ๋ ค๋ ๋ฉ์๋์ @Retryable ์ด๋ ธํ ์ด์ ์ ์ง์ ํด์ค๋ค.
- ์ฌ์๋๊ฐ ์๋ฃ๋๋ ์์ ์์ ์คํํ๊ณ ์ถ์๋ ์ ์ธํ๋ ์ด๋ ธํ ์ด์ , @Retryable ๋์ผํ ํด๋์ค์์ ์ ์ธ๋์ด์ผ ํ๊ณ return type ์ @Retryable์ ์ง์ ํ ๋ฉ์๋์ ๋์ผํด์ผ ํ๋ค.
Retry Rest Template
์ด๋ ๊ฒ springframework ์์ ์ ๊ณตํด์ฃผ๋ spring-retry ๋ฅผ ์ด์ฉํด์ ์ด๋ฒ ํฌ์คํ ์ ๋ชฉํ์ธ ์ฌ์๋๋ฅผ ํ๋ Retry Rest Template ๋ฅผ ๊ตฌ์ฑํด๋ณด์. ์ฐ์ , RestTemplate ๋ฅผ Bean ์ผ๋ก ๋ฑ๋กํ๊ณ , ์์์ ์ด์ผ๊ธฐ ํ ์ด๋ ธํ ์ด์ ๋ค๋ก ๊ตฌ์ฑํด๋ณด์.
@EnableRetry
@Configuration
public class RetryableRestTemplateConfiguration {
@Bean
public RestTemplate retryableRestTemplate() {
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory(); // 1
clientHttpRequestFactory.setReadTimeout(2000);
clientHttpRequestFactory.setConnectTimeout(500);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory) {
@Override
@Retryable(value = RestClientException.class, maxAttempts = 3, backoff = @Backoff(delay = 1000)) // 2
public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType)
throws RestClientException {
return super.exchange(url, method, requestEntity, responseType);
}
@Recover
public <T> ResponseEntity<String> exchangeRecover(RestClientException e) {
return ResponseEntity.badRequest().body("bad request T.T"); // 3
}
};
return restTemplate;
}
}
- SimpleClientHttpRequestFactory ๋ฅผ ๋ง๋ค๊ณ ๊ฐ ํ์์์์ ์ค์ ํด์ค ๋ค์ RestTemplate ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒจ์ค๋ค.
- ์ฌ์ฉํ๋ ๊ณณ์์ exchange ๋ฉ์๋๋ฅผ ์ด์ฉํ ๊ฒ์ด๋ฏ๋ก ํด๋น ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ ํด์ค๋ค. ๋จผ์ ํด๋น ๋ฉ์๋์์ “RestClientException"์ด ๋ฐ์ํ ๊ฒฝ์ฐ Retry ๋ก์ง์ ์ํํ๋ค๊ณ ์ ํด์ฃผ๊ณ , ์ต๋ ์๋๋ 3๋ฒ, backoff ์ค์ ์ค delay๋ฅผ 1000ms(1์ด)๋ก ์ง์ ํด์ ์ฌ์๋๊ฐ ์งํ๋๋๋ก ํด์ค๋ค.
- 2 ์์ ์ง์ ํ ์ฌ์๋๊ฐ ๋๋๋ฉด (์ฌ์๋๋ฅผ ์ ๋ถ ๋ค ํ๋ฉด) ํด๋น ๋ฉ์๋๋ฅผ ์ํํ๊ฒ ๋์ด์๊ณ , ์์๋ก ์๋ต์ ์ง์ ํ ๋ฌธ๊ตฌ๋ฅผ ๋๊ฒจ์ค๋ค.
์ด๋ ๊ฒ ํ๊ณ ์ค์ ๋ก ์ฌ์ฉํ๋ ๋ก์ง์์ ์ผ๋ถ๋ฌ ์๋ชป๋ URL์ ํธ์ถํด ๋ณด๋๋ก ํ์. ๊ทธ๋ฆฌ๊ณ ์ ๋ก๊ทธ๋ฅผ ์์ธํ ๋ณด๋๋ก application.properties ์ “debug=true” ์ค์ ์ ํด์ค๋ค.