diff --git a/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLConfiguration.java b/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLConfiguration.java index baca0706..a6a9afeb 100644 --- a/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLConfiguration.java +++ b/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLConfiguration.java @@ -17,6 +17,8 @@ import graphql.schema.GraphQLSchema; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.function.Supplier; import lombok.Getter; @@ -31,6 +33,7 @@ public class GraphQLConfiguration { @Getter private final long asyncTimeout; private final ContextSetting contextSetting; private final GraphQLResponseCacheManager responseCacheManager; + @Getter private final Executor asyncExecutor; private HttpRequestHandler requestHandler; private GraphQLConfiguration( @@ -43,8 +46,10 @@ private GraphQLConfiguration( long asyncTimeout, ContextSetting contextSetting, Supplier batchInputPreProcessor, - GraphQLResponseCacheManager responseCacheManager) { + GraphQLResponseCacheManager responseCacheManager, + Executor asyncExecutor) { this.invocationInputFactory = invocationInputFactory; + this.asyncExecutor = asyncExecutor; this.graphQLInvoker = graphQLInvoker != null ? graphQLInvoker : queryInvoker.toGraphQLInvoker(); this.objectMapper = objectMapper; this.listeners = listeners; @@ -137,6 +142,7 @@ public static class Builder { private Supplier batchInputPreProcessorSupplier = NoOpBatchInputPreProcessor::new; private GraphQLResponseCacheManager responseCacheManager; + private Executor asyncExecutor = Executors.newCachedThreadPool(); private Builder(GraphQLInvocationInputFactory.Builder invocationInputFactoryBuilder) { this.invocationInputFactoryBuilder = invocationInputFactoryBuilder; @@ -192,6 +198,11 @@ public Builder asyncTimeout(long asyncTimeout) { return this; } + public Builder with(Executor asyncExecutor) { + this.asyncExecutor = asyncExecutor; + return this; + } + public Builder with(ContextSetting contextSetting) { if (contextSetting != null) { this.contextSetting = contextSetting; @@ -231,7 +242,8 @@ public GraphQLConfiguration build() { asyncTimeout, contextSetting, batchInputPreProcessorSupplier, - responseCacheManager); + responseCacheManager, + asyncExecutor); } } } diff --git a/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/HttpRequestInvokerImpl.java b/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/HttpRequestInvokerImpl.java index 49e55a0b..9d10e398 100644 --- a/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/HttpRequestInvokerImpl.java +++ b/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/HttpRequestInvokerImpl.java @@ -72,13 +72,15 @@ private void invokeAndHandleAsync( } }; asyncContext.addListener(timeoutListener); - asyncContext.start( - () -> { - FutureExecutionResult futureResult = invoke(invocationInput, request, response); - futureHolder.set(futureResult); - handle(futureResult, request, response, listenerHandler) - .thenAccept(it -> asyncContext.complete()); - }); + configuration + .getAsyncExecutor() + .execute( + () -> { + FutureExecutionResult futureResult = invoke(invocationInput, request, response); + futureHolder.set(futureResult); + handle(futureResult, request, response, listenerHandler) + .thenAccept(it -> asyncContext.complete()); + }); } private CompletableFuture handle( diff --git a/graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestUtils.groovy b/graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestUtils.groovy index c15b7ff0..9711db57 100644 --- a/graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestUtils.groovy +++ b/graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestUtils.groovy @@ -1,7 +1,6 @@ package graphql.kickstart.servlet import com.google.common.io.ByteStreams -import graphql.Directives import graphql.Scalars import graphql.execution.reactive.SingleSubscriberPublisher import graphql.kickstart.execution.context.ContextSetting @@ -15,7 +14,9 @@ import graphql.schema.idl.SchemaGenerator import graphql.schema.idl.SchemaParser import graphql.schema.idl.TypeRuntimeWiring import graphql.schema.idl.errors.SchemaProblem +import org.jetbrains.annotations.NotNull +import java.util.concurrent.Executor import java.util.concurrent.atomic.AtomicReference class TestUtils { @@ -59,6 +60,7 @@ class TestUtils { .with(schema) .with(contextSetting) .with(contextBuilder) + .with(executor()) .build()) servlet.init(null) return servlet @@ -96,9 +98,19 @@ class TestUtils { if (listeners != null) { configBuilder.with(Arrays.asList(listeners)) } + configBuilder.with(executor()); configBuilder.build() } + private static Executor executor() { + new Executor() { + @Override + void execute(@NotNull Runnable command) { + command.run() + } + } + } + static def createBatchExecutionHandler() { new TestBatchInputPreProcessor() }