diff --git a/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTaskDecorator.java b/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTaskDecorator.java new file mode 100644 index 00000000..27a8bc2d --- /dev/null +++ b/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTaskDecorator.java @@ -0,0 +1,7 @@ +package graphql.kickstart.servlet; + +public interface AsyncTaskDecorator { + + Runnable decorate(Runnable runnable); + +} diff --git a/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTaskExecutor.java b/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTaskExecutor.java new file mode 100644 index 00000000..7a2f0f26 --- /dev/null +++ b/graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTaskExecutor.java @@ -0,0 +1,22 @@ +package graphql.kickstart.servlet; + +import java.util.concurrent.Executor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +class AsyncTaskExecutor implements Executor { + + private final Executor executor; + private final AsyncTaskDecorator taskDecorator; + + @Override + public void execute(@NonNull Runnable command) { + if (taskDecorator != null) { + Runnable decorated = taskDecorator.decorate(command); + executor.execute(decorated); + } else { + executor.execute(command); + } + } +} 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 a6a9afeb..f009889e 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 @@ -18,7 +18,9 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import lombok.Getter; @@ -142,7 +144,10 @@ public static class Builder { private Supplier batchInputPreProcessorSupplier = NoOpBatchInputPreProcessor::new; private GraphQLResponseCacheManager responseCacheManager; - private Executor asyncExecutor = Executors.newCachedThreadPool(); + private int asyncCorePoolSize = 10; + private int asyncMaxPoolSize = 200; + private Executor asyncExecutor; + private AsyncTaskDecorator asyncTaskDecorator; private Builder(GraphQLInvocationInputFactory.Builder invocationInputFactoryBuilder) { this.invocationInputFactoryBuilder = invocationInputFactoryBuilder; @@ -203,6 +208,16 @@ public Builder with(Executor asyncExecutor) { return this; } + public Builder asyncCorePoolSize(int asyncCorePoolSize) { + this.asyncCorePoolSize = asyncCorePoolSize; + return this; + } + + public Builder asyncMaxPoolSize(int asyncMaxPoolSize) { + this.asyncMaxPoolSize = asyncMaxPoolSize; + return this; + } + public Builder with(ContextSetting contextSetting) { if (contextSetting != null) { this.contextSetting = contextSetting; @@ -229,6 +244,27 @@ public Builder with(GraphQLResponseCacheManager responseCache) { return this; } + public Builder with(AsyncTaskDecorator asyncTaskDecorator) { + this.asyncTaskDecorator = asyncTaskDecorator; + return this; + } + + private Executor getAsyncExecutor() { + if (asyncExecutor != null) { + return asyncExecutor; + } + return new ThreadPoolExecutor( + asyncCorePoolSize, + asyncMaxPoolSize, + 60, + TimeUnit.SECONDS, + new LinkedBlockingQueue<>(Integer.MAX_VALUE)); + } + + private Executor getAsyncTaskExecutor() { + return new AsyncTaskExecutor(getAsyncExecutor(), asyncTaskDecorator); + } + public GraphQLConfiguration build() { return new GraphQLConfiguration( this.invocationInputFactory != null @@ -243,7 +279,7 @@ public GraphQLConfiguration build() { contextSetting, batchInputPreProcessorSupplier, responseCacheManager, - asyncExecutor); + getAsyncTaskExecutor()); } } }