diff --git a/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java b/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java index 43792019..b1bc609c 100644 --- a/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java +++ b/openapi-validation-core/src/main/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidator.java @@ -12,25 +12,25 @@ import com.getyourguide.openapi.validation.api.model.ValidatorConfiguration; import com.getyourguide.openapi.validation.core.validator.OpenApiInteractionValidatorWrapper; import java.nio.charset.StandardCharsets; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; import org.apache.http.client.utils.URLEncodedUtils; @Slf4j public class OpenApiRequestValidator { - private final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 2, 1000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10)); - + private final ThreadPoolExecutor threadPoolExecutor; private final OpenApiInteractionValidatorWrapper validator; private final ValidationReportHandler validationReportHandler; public OpenApiRequestValidator( + ThreadPoolExecutor threadPoolExecutor, ValidationReportHandler validationReportHandler, MetricsReporter metricsReporter, String specificationFilePath, ValidatorConfiguration configuration ) { + this.threadPoolExecutor = threadPoolExecutor; this.validator = new OpenApiInteractionValidatorFactory().build(specificationFilePath, configuration); this.validationReportHandler = validationReportHandler; @@ -42,11 +42,19 @@ public boolean isReady() { } public void validateRequestObjectAsync(final RequestMetaData request, String requestBody) { - threadPool.execute(() -> validateRequestObject(request, requestBody)); + executeAsync(() -> validateRequestObject(request, requestBody)); } public void validateResponseObjectAsync(final RequestMetaData request, ResponseMetaData response, final String responseBody) { - threadPool.execute(() -> validateResponseObject(request, response, responseBody)); + executeAsync(() -> validateResponseObject(request, response, responseBody)); + } + + private void executeAsync(Runnable command) { + try { + threadPoolExecutor.execute(command); + } catch (RejectedExecutionException ignored) { + // ignored + } } public ValidationResult validateRequestObject(final RequestMetaData request, String requestBody) { diff --git a/openapi-validation-core/src/test/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidatorTest.java b/openapi-validation-core/src/test/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidatorTest.java new file mode 100644 index 00000000..ffe3dae9 --- /dev/null +++ b/openapi-validation-core/src/test/java/com/getyourguide/openapi/validation/core/OpenApiRequestValidatorTest.java @@ -0,0 +1,40 @@ +package com.getyourguide.openapi.validation.core; + +import static org.mockito.Mockito.mock; + +import com.getyourguide.openapi.validation.api.metrics.MetricsReporter; +import com.getyourguide.openapi.validation.api.model.ValidatorConfiguration; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadPoolExecutor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class OpenApiRequestValidatorTest { + + private ThreadPoolExecutor threadPoolExecutor; + + private OpenApiRequestValidator openApiRequestValidator; + + @BeforeEach + public void setup() { + threadPoolExecutor = mock(); + ValidationReportHandler validationReportHandler = mock(); + MetricsReporter metricsReporter = mock(); + + openApiRequestValidator = new OpenApiRequestValidator( + threadPoolExecutor, + validationReportHandler, + metricsReporter, + "", + new ValidatorConfiguration(null, null, null) + ); + } + + @Test + public void testWhenThreadPoolExecutorRejectsExecutionThenItShouldNotThrow() { + Mockito.doThrow(new RejectedExecutionException()).when(threadPoolExecutor).execute(Mockito.any()); + + openApiRequestValidator.validateRequestObjectAsync(mock(), null); + } +} diff --git a/spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java b/spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java index 7f3d090e..269099f8 100644 --- a/spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java +++ b/spring-boot-starter/spring-boot-starter-core/src/main/java/com/getyourguide/openapi/validation/autoconfigure/LibraryAutoConfiguration.java @@ -20,6 +20,9 @@ import com.getyourguide.openapi.validation.core.throttle.ValidationReportThrottler; import com.getyourguide.openapi.validation.core.throttle.ValidationReportThrottlerNone; import java.util.Optional; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import lombok.AllArgsConstructor; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -96,7 +99,17 @@ public OpenApiRequestValidator openApiRequestValidator( MetricsReporter metricsReporter, ValidatorConfiguration validatorConfiguration ) { + var threadPoolExecutor = new ThreadPoolExecutor( + 2, + 2, + 1000L, + TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(10), + new ThreadPoolExecutor.DiscardPolicy() + ); + return new OpenApiRequestValidator( + threadPoolExecutor, validationReportHandler, metricsReporter, properties.getSpecificationFilePath(),