#26 pharmacy: spring retry
This commit is contained in:
@@ -26,6 +26,8 @@ repositories {
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.retry:spring-retry'
|
||||
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
|
||||
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
|
||||
@@ -42,6 +44,10 @@ dependencies {
|
||||
// testcontainers
|
||||
testImplementation 'org.testcontainers:spock:1.17.6'
|
||||
testImplementation 'org.testcontainers:mariadb:1.17.6'
|
||||
|
||||
// mockWebServer
|
||||
testImplementation 'com.squareup.okhttp3:okhttp:4.10.0'
|
||||
testImplementation 'com.squareup.okhttp3:mockwebserver:4.10.0'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
|
||||
@@ -7,6 +7,9 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Recover;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@@ -24,11 +27,16 @@ public class KakaoAddressSearchService {
|
||||
@Value("${kakao.rest.api.key}")
|
||||
private String kakaoRestApiKey;
|
||||
|
||||
@Retryable(
|
||||
value = {RuntimeException.class},
|
||||
maxAttempts = 2,
|
||||
backoff = @Backoff(delay = 2000)
|
||||
)
|
||||
public KakaoApiResponseDto requestAddressSearch(String address) {
|
||||
|
||||
if (ObjectUtils.isEmpty(address)) return null;
|
||||
|
||||
URI uri = kakaoUriBuilderService.builderUriByAddressSearch(address);
|
||||
URI uri = kakaoUriBuilderService.buildUriByAddressSearch(address);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set(HttpHeaders.AUTHORIZATION, "KakaoAK " + kakaoRestApiKey);
|
||||
@@ -38,4 +46,10 @@ public class KakaoAddressSearchService {
|
||||
// kakao api 호출
|
||||
return restTemplate.exchange(uri, HttpMethod.GET, httpEntity, KakaoApiResponseDto.class).getBody();
|
||||
}
|
||||
|
||||
@Recover
|
||||
public KakaoApiResponseDto recover(RuntimeException e, String address) {
|
||||
log.error("All the retries failed. address: {}, error: {}", address, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public class KakaoUriBuilderService {
|
||||
|
||||
private static final String KAKAO_LOCAL_SEARCH_ADDRESS_URL = "https://dapi.kakao.com/v2/local/search/address.json";
|
||||
|
||||
public URI builderUriByAddressSearch(String address) {
|
||||
public URI buildUriByAddressSearch(String address) {
|
||||
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(KAKAO_LOCAL_SEARCH_ADDRESS_URL);
|
||||
uriBuilder.queryParam("query", address);
|
||||
|
||||
16
road/src/main/java/com/example/road/config/RetryConfig.java
Normal file
16
road/src/main/java/com/example/road/config/RetryConfig.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.example.road.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.retry.annotation.EnableRetry;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
|
||||
@EnableRetry
|
||||
@Configuration
|
||||
public class RetryConfig {
|
||||
|
||||
// @Bean
|
||||
// public RetryTemplate retryTemplate() {
|
||||
// return new RetryTemplate();
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.example.road.api.service
|
||||
|
||||
import com.example.road.AbstractIntegrationContainerBaseTest
|
||||
import com.example.road.api.dto.DocumentDto
|
||||
import com.example.road.api.dto.KakaoApiResponseDto
|
||||
import com.example.road.api.dto.MetaDto
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.spockframework.spring.SpringBean
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.MediaType
|
||||
|
||||
class KakaoAddressSearchServiceRetryTest extends AbstractIntegrationContainerBaseTest {
|
||||
|
||||
@Autowired
|
||||
private KakaoAddressSearchService kakaoAddressSearchService;
|
||||
|
||||
@SpringBean
|
||||
private KakaoUriBuilderService kakaoUriBuilderService = Mock();
|
||||
|
||||
private MockWebServer mockWebServer;
|
||||
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
private String inputAddress = "서울 성북구 종암로 10길";
|
||||
|
||||
def setup() {
|
||||
mockWebServer = new MockWebServer();
|
||||
mockWebServer.start();
|
||||
println mockWebServer.port;
|
||||
println mockWebServer.url("/")
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
mockWebServer.shutdown();
|
||||
}
|
||||
|
||||
def "requestAddressSearch retry success"() {
|
||||
given:
|
||||
def metaDto = new MetaDto(1)
|
||||
def documentDto = DocumentDto.builder()
|
||||
.addressName(inputAddress)
|
||||
.build();
|
||||
def expectedResponse = new KakaoApiResponseDto(metaDto, Arrays.asList(documentDto));
|
||||
def uri = mockWebServer.url("/").uri();
|
||||
|
||||
when:
|
||||
mockWebServer.enqueue(new MockResponse().setResponseCode(504))
|
||||
mockWebServer.enqueue(new MockResponse().setResponseCode(200)
|
||||
.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setBody(mapper.writeValueAsString(expectedResponse)))
|
||||
|
||||
def kakaoApiResult = kakaoAddressSearchService.requestAddressSearch(inputAddress)
|
||||
def takeRequest = mockWebServer.takeRequest()
|
||||
|
||||
then:
|
||||
2 * kakaoUriBuilderService.buildUriByAddressSearch(inputAddress) >> uri
|
||||
takeRequest.getMethod() == "GET"
|
||||
kakaoApiResult.getDocumentList().size() == 1
|
||||
kakaoApiResult.getMetaDto().totalCount == 1
|
||||
kakaoApiResult.getDocumentList().get(0).getAddressName() == inputAddress
|
||||
}
|
||||
|
||||
def "requestAddressSearch retry fail "() {
|
||||
given:
|
||||
def uri = mockWebServer.url("/").uri()
|
||||
|
||||
when:
|
||||
mockWebServer.enqueue(new MockResponse().setResponseCode(504))
|
||||
mockWebServer.enqueue(new MockResponse().setResponseCode(504))
|
||||
|
||||
def result = kakaoAddressSearchService.requestAddressSearch(inputAddress)
|
||||
|
||||
then:
|
||||
2 * kakaoUriBuilderService.buildUriByAddressSearch(inputAddress) >> uri
|
||||
result == null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class KakaoUriBuilderServiceTest extends Specification {
|
||||
def charset = StandardCharsets.UTF_8;
|
||||
|
||||
when:
|
||||
def uri = kakaoUriBuilderService.builderUriByAddressSearch(address)
|
||||
def uri = kakaoUriBuilderService.buildUriByAddressSearch(address)
|
||||
def decodedResult = URLDecoder.decode(uri.toString(), charset)
|
||||
|
||||
then:
|
||||
|
||||
Reference in New Issue
Block a user