Skip to content
Snippets Groups Projects
Commit d496d6a2 authored by Neelesh Thakur's avatar Neelesh Thakur
Browse files

Merge branch 'retry' into 'master'

add retries for schema service and all other service calls

See merge request !201
parents 5a02fe9c 070abe68
No related branches found
No related tags found
1 merge request!201add retries for schema service and all other service calls
Pipeline #67309 failed
......@@ -544,7 +544,7 @@ The following software have components provided under the terms of this license:
- Proton-J (from https://repo1.maven.org/maven2/org/apache/qpid/proton-j)
- QpidJMS Client (from )
- RabbitMQ Java Client (from https://www.rabbitmq.com)
- Reactive Streams Netty driver (from https://github.com/reactor/reactor-netty)
- Reactor Netty with all modules (from https://github.com/reactor/reactor-netty)
- Retrofit (from https://repo1.maven.org/maven2/com/squareup/retrofit2/retrofit)
- Servlet Specification 2.5 API (from http://jetty.mortbay.org)
- SnakeYAML (from http://www.snakeyaml.org)
......@@ -552,6 +552,7 @@ The following software have components provided under the terms of this license:
- Spring AMQP Core (from https://projects.spring.io/spring-amqp)
- Spring AOP (from https://github.com/spring-projects/spring-framework)
- Spring Beans (from https://github.com/spring-projects/spring-framework)
- Spring Boot AOP Starter (from http://projects.spring.io/spring-boot/)
- Spring Boot Actuator (from http://projects.spring.io/spring-boot/)
- Spring Boot Actuator Starter (from http://projects.spring.io/spring-boot/)
- Spring Boot Log4j 2 Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-log4j2)
......@@ -593,12 +594,12 @@ The following software have components provided under the terms of this license:
- aggs-matrix-stats (from https://github.com/elastic/elasticsearch)
- asm (from http://asm.ow2.io/)
- asm (from http://asm.ow2.io/)
- cli (from https://github.com/elastic/elasticsearch)
- compiler (from http://github.com/spullara/mustache.java)
- datastore-v1-proto-client (from https://repo1.maven.org/maven2/com/google/cloud/datastore/datastore-v1-proto-client)
- elasticsearch (from https://repo1.maven.org/maven2/org/elasticsearch/elasticsearch)
- elasticsearch-cli (from https://github.com/elastic/elasticsearch)
- elasticsearch-core (from https://github.com/elastic/elasticsearch)
- elasticsearch-geo (from https://github.com/elastic/elasticsearch)
- elasticsearch-secure-sm (from https://github.com/elastic/elasticsearch)
- elasticsearch-x-content (from https://github.com/elastic/elasticsearch)
- error-prone annotations (from https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations)
- error-prone annotations (from https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations)
......@@ -701,14 +702,13 @@ The following software have components provided under the terms of this license:
- rest (from https://github.com/elastic/elasticsearch)
- rest-high-level (from https://github.com/elastic/elasticsearch)
- rxjava (from https://github.com/ReactiveX/RxJava)
- secure-sm (from https://github.com/elastic/elasticsearch)
- server (from https://github.com/elastic/elasticsearch)
- spring-boot (from https://spring.io/projects/spring-boot)
- spring-boot-actuator-autoconfigure (from https://spring.io/projects/spring-boot)
- spring-boot-autoconfigure (from https://spring.io/projects/spring-boot)
- spring-boot-configuration-processor (from https://spring.io/projects/spring-boot)
- spring-boot-dependencies (from https://spring.io/projects/spring-boot)
- spring-boot-starter-amqp (from https://spring.io/projects/spring-boot)
- spring-boot-starter-aop (from https://spring.io/projects/spring-boot)
- spring-boot-starter-data-mongodb (from https://spring.io/projects/spring-boot)
- spring-boot-starter-jersey (from https://spring.io/projects/spring-boot)
- spring-boot-starter-json (from https://spring.io/projects/spring-boot)
......@@ -1101,7 +1101,6 @@ The following software have components provided under the terms of this license:
- JOpt Simple (from http://pholser.github.com/jopt-simple)
- JUL to SLF4J bridge (from http://www.slf4j.org)
- Java Client Runtime for AutoRest (from https://github.com/Azure/autorest-clientruntime-for-java)
- Java JWT (from http://www.jwt.io)
- Lucene Core (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-core)
- Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
- Microsoft Application Insights Java SDK Spring Boot starter (from https://github.com/Microsoft/ApplicationInsights-Java)
......@@ -1134,6 +1133,7 @@ The following software have components provided under the terms of this license:
- adal4j (from https://github.com/AzureAD/azure-activedirectory-library-for-java)
- azure-documentdb (from https://azure.microsoft.com/en-us/services/cosmos-db/)
- documentdb-bulkexecutor (from http://azure.microsoft.com/en-us/services/documentdb/)
- java jwt (from https://github.com/auth0/java-jwt)
- micrometer-core (from https://github.com/micrometer-metrics/micrometer)
- mockito-core (from https://github.com/mockito/mockito)
- mockito-core (from https://github.com/mockito/mockito)
......
......@@ -28,6 +28,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.function.Predicate;
/**
* This class handles retry configuration logic for calls made to <prefix>/storage/v2/query/records:batch
......@@ -50,23 +51,25 @@ public class RetryPolicy {
/**
* @return RetryConfig with 3 attempts and 1 sec wait time
*/
public RetryConfig retryConfig() {
public RetryConfig retryConfig(Predicate<HttpResponse> predicate) {
return RetryConfig.<HttpResponse>custom()
.maxAttempts(attempts)
.waitDuration(Duration.ofMillis(waitDuration))
.retryOnResult(response -> isRetryRequired(response))
.retryOnResult(predicate)
.build();
}
/**
* Unfound records get listed under a JsonArray "notFound" in the http json response
*
* @param response
* @return if there are elements in "notFound" returns true, else false
*/
private boolean isRetryRequired(HttpResponse response) {
if (response == null || response.getBody().isEmpty()) {
return false;
}
public boolean batchRetryPolicy(HttpResponse response) {
if (retryOnEmptyResponse(response)) return false;
if (defaultResponseRetry(response)) return true;
JsonObject jsonObject = new JsonParser().parse(response.getBody()).getAsJsonObject();
JsonElement notFoundElement = (JsonArray) jsonObject.get(RECORD_NOT_FOUND);
if (notFoundElement == null ||
......@@ -75,7 +78,37 @@ public class RetryPolicy {
notFoundElement.getAsJsonArray().isJsonNull()) {
return false;
}
log.info("Retry is set true");
log.info("Storage batch API retry");
return true;
}
public boolean schemaRetryPolicy(HttpResponse response) {
if (retryOnEmptyResponse(response)) return false;
if (defaultResponseRetry(response)) return true;
if (response.getResponseCode() == 404) {
log.info("Schema API retry");
return true;
}
return false;
}
public boolean defaultRetryPolicy(HttpResponse response) {
if (retryOnEmptyResponse(response)) return false;
return defaultResponseRetry(response);
}
private boolean retryOnEmptyResponse(HttpResponse response) {
return response == null || response.getBody().isEmpty();
}
private boolean defaultResponseRetry(HttpResponse response) {
if (response.getResponseCode() <= 501) return false;
log.info(String.format("Default retry, response code: %s", response.getResponseCode()));
return true;
}
}
......@@ -41,6 +41,7 @@ import java.util.function.Supplier;
public class UrlFetchServiceAzureImpl implements IUrlFetchService {
public static final String STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST_URL = "storage/v2/query/records:batch";
public static final String SCHEMA_SERVICE_HOST_URL = "api/schema-service/v1/schema";
@Autowired
private RetryPolicy policy;
......@@ -50,6 +51,7 @@ public class UrlFetchServiceAzureImpl implements IUrlFetchService {
@Autowired
private JaxRsDpsLog logger;
/**
* this method invokes retryFunction only for <prefix>/storage/v2/query/records:batch
* calls otherwise invokes UrlFetchService.sendRequest(FetchServiceHttpRequest request)
......@@ -60,14 +62,7 @@ public class UrlFetchServiceAzureImpl implements IUrlFetchService {
*/
@Override
public HttpResponse sendRequest(FetchServiceHttpRequest httpRequest) throws URISyntaxException {
HttpResponse output;
if (httpRequest.getUrl().contains(STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST_URL)) {
output = this.retryFunction(httpRequest);
if (output != null) {
return output;
}
}
return this.urlFetchService.sendRequest(httpRequest);
return this.retryFunction(httpRequest);
}
/**
......@@ -78,7 +73,15 @@ public class UrlFetchServiceAzureImpl implements IUrlFetchService {
* @return null if URISyntaxException is caught else returns HttpResponse
*/
private HttpResponse retryFunction(FetchServiceHttpRequest request) {
RetryConfig config = this.policy.retryConfig();
RetryConfig config;
if (request.getUrl().contains(STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST_URL)) {
config = this.policy.retryConfig(response -> this.policy.batchRetryPolicy(response));
} else if (request.getUrl().contains(SCHEMA_SERVICE_HOST_URL)) {
config = this.policy.retryConfig(response -> this.policy.schemaRetryPolicy(response));
} else {
config = this.policy.retryConfig(response -> this.policy.defaultRetryPolicy(response));
}
RetryRegistry registry = RetryRegistry.of(config);
Retry retry = registry.retry("retryPolicy", config);
......
......@@ -131,7 +131,7 @@ public class RetryPolicyTest {
@Test
public void retry_should_be_true_for_jsonResponseWithNotFound() {
RetryConfig config = this.retryPolicy.retryConfig();
RetryConfig config = this.retryPolicy.retryConfig(response -> this.retryPolicy.batchRetryPolicy(response));
Predicate<HttpResponse> retry = config.getResultPredicate();
response.setBody(JSON_RESPONSE_WITH_NOT_FOUND);
assert retry != null;
......@@ -142,7 +142,7 @@ public class RetryPolicyTest {
@Test
public void retry_should_be_false_for_jsonResponse1WithOut_NotFound() {
RetryConfig config = this.retryPolicy.retryConfig();
RetryConfig config = this.retryPolicy.retryConfig(response -> this.retryPolicy.batchRetryPolicy(response));
Predicate<HttpResponse> retry = config.getResultPredicate();
response.setBody(JSON_RESPONSE1_WITHOUT_NOT_FOUND);
boolean value = retry.test(response);
......@@ -152,7 +152,7 @@ public class RetryPolicyTest {
@Test
public void retry_should_be_false_for_jsonResponse2WithOut_NotFound() {
RetryConfig config = this.retryPolicy.retryConfig();
RetryConfig config = this.retryPolicy.retryConfig(response -> this.retryPolicy.batchRetryPolicy(response));
Predicate<HttpResponse> retry = config.getResultPredicate();
response.setBody(JSON_RESPONSE2_WITHOUT_NOT_FOUND);
boolean value = retry.test(response);
......
......@@ -14,8 +14,6 @@
package org.opengroup.osdu.indexer.azure.service;
import io.github.resilience4j.retry.RetryConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
......@@ -26,12 +24,8 @@ import org.opengroup.osdu.core.common.http.UrlFetchServiceImpl;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.model.http.HttpResponse;
import java.time.Duration;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
......@@ -95,45 +89,43 @@ public class UrlFetchServiceAzureImplTest {
" \"conversionStatuses\":[]\n" +
"}";
private static final String url = "https://demo/api/storage/v2/query/records:batch";
private static final String url2 = "https://demo/api/storage/v2/schemas";
@Before
public void setUp() {
when(this.retryPolicy.retryConfig()).thenReturn(new RetryPolicy().retryConfig());
}
private static final String BATCH_API_URL = "https://demo/api/storage/v2/query/records:batch";
private static final String STORAGE_API_URL = "https://demo/api/storage/v2/schemas";
private static final String SCHEMA_API_URL = "https://demo/api/schema-service/v1/schema/osdu:file:gom:1.0.0";
@Test
public void shouldRetry_ForJSON1_when_storageQueryRecordCallIsMade() throws Exception {
response.setBody(JSON1);
httpRequest.setUrl(url);
when(urlFetchServiceAzure.sendRequest(httpRequest)).thenReturn(response);
httpRequest.setUrl(BATCH_API_URL);
when(this.retryPolicy.retryConfig(any())).thenReturn(new RetryPolicy().retryConfig(response -> this.retryPolicy.batchRetryPolicy(response)));
when(urlFetchService.sendRequest(httpRequest)).thenReturn(response);
urlFetchServiceAzure.sendRequest(httpRequest);
verify(urlFetchService, atMost(4)).sendRequest(httpRequest);
}
@Test
public void shouldNotRetry_ForJSON2_when_storageQueryRecordCallIsMade() throws Exception {
response.setBody(JSON2);
httpRequest.setUrl(url);
when(urlFetchServiceAzure.sendRequest(httpRequest)).thenReturn(response);
public void shouldRetry_ForJSON1_when_schemaRecordCallIsMade() throws Exception {
response.setBody(JSON1);
httpRequest.setUrl(SCHEMA_API_URL);
when(this.retryPolicy.retryConfig(any())).thenReturn(new RetryPolicy().retryConfig(response -> this.retryPolicy.schemaRetryPolicy(response)));
when(urlFetchService.sendRequest(httpRequest)).thenReturn(response);
urlFetchServiceAzure.sendRequest(httpRequest);
verify(urlFetchService, atMost(2)).sendRequest(httpRequest);
}
verify(urlFetchService, atMost(4)).sendRequest(httpRequest);
}
@Test
public void retryFunction_shouldNotBeCalled() throws Exception {
httpRequest.setUrl(url2);
public void shouldRetry_when_anyOtherCallIsMade() throws Exception {
response.setBody(JSON2);
httpRequest.setUrl(STORAGE_API_URL);
when(this.retryPolicy.retryConfig(any())).thenReturn(new RetryPolicy().retryConfig(response -> this.retryPolicy.defaultRetryPolicy(response)));
when(urlFetchService.sendRequest(httpRequest)).thenReturn(response);
urlFetchServiceAzure.sendRequest(httpRequest);
verify(urlFetchService, times(1)).sendRequest(httpRequest);
}
verify(urlFetchService, atMost(4)).sendRequest(httpRequest);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment