#26 pharmacy: spring retry

This commit is contained in:
haerong22
2022-12-18 11:44:43 +09:00
parent 96315109e3
commit e3a35b2fbd
6 changed files with 120 additions and 3 deletions

View File

@@ -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') {

View File

@@ -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;
}
}

View File

@@ -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);

View 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();
// }
}

View File

@@ -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
}
}

View File

@@ -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: