Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ TARGET_COMPATIBILITY=1.8
LIB_GRAPHQL_JAVA_VER=16.2
LIB_EXTENDED_SCALARS_VER=16.0.1
LIB_SPRING_BOOT_VER=2.4.5
LIB_GRAPHQL_SERVLET_VER=11.1.1
LIB_GRAPHQL_SERVLET_VER=11.2.0-SNAPSHOT
LIB_GRAPHQL_JAVA_TOOLS_VER=11.0.1
LIB_GRAPHQL_ANNOTATIONS_VER=8.3
LIB_REFLECTIONS_VER=0.9.11
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package graphql.kickstart.autoconfigure.web.servlet;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "graphql.servlet.async")
public class AsyncServletProperties {

private boolean enabled = true;
private long timeout = 30000;
private boolean delegateSecurityContext = true;
private Threads threads = new Threads();

@Data
static class Threads {
private int min = 10;
private int max = 200;
private String namePrefix = "graphql-exec-";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ public class GraphQLServletProperties {
private boolean exceptionHandlersEnabled = false;
private long subscriptionTimeout = 0;
private ContextSetting contextSetting = ContextSetting.PER_QUERY_WITH_INSTRUMENTATION;
private long asyncTimeout = 30000;
private boolean asyncModeEnabled = true;
/** @deprecated Use <tt>graphql.servlet.async.timeout</tt> instead */
@Deprecated private Long asyncTimeout;
/** @deprecated Use <tt>graphql.servlet.async.enabled</tt> instead */
@Deprecated private Boolean asyncModeEnabled;

private String tracingEnabled = "false";
private boolean actuatorMetrics;
private Integer maxQueryComplexity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import graphql.kickstart.execution.config.ObjectMapperProvider;
import graphql.kickstart.execution.error.GraphQLErrorHandler;
import graphql.kickstart.servlet.AbstractGraphQLHttpServlet;
import graphql.kickstart.servlet.AsyncTaskDecorator;
import graphql.kickstart.servlet.GraphQLConfiguration;
import graphql.kickstart.servlet.GraphQLHttpServlet;
import graphql.kickstart.servlet.cache.GraphQLResponseCacheManager;
Expand All @@ -61,11 +62,13 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import javax.servlet.MultipartConfigElement;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand All @@ -81,6 +84,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
Expand All @@ -101,14 +105,15 @@
havingValue = "true",
matchIfMissing = true)
@AutoConfigureAfter({GraphQLJavaToolsAutoConfiguration.class, JacksonAutoConfiguration.class})
@EnableConfigurationProperties({GraphQLServletProperties.class})
@EnableConfigurationProperties({GraphQLServletProperties.class, AsyncServletProperties.class})
public class GraphQLWebAutoConfiguration {

public static final String QUERY_EXECUTION_STRATEGY = "queryExecutionStrategy";
public static final String MUTATION_EXECUTION_STRATEGY = "mutationExecutionStrategy";
public static final String SUBSCRIPTION_EXECUTION_STRATEGY = "subscriptionExecutionStrategy";

private final GraphQLServletProperties graphQLServletProperties;
private final AsyncServletProperties asyncServletProperties;
private final ErrorHandlerSupplier errorHandlerSupplier = new ErrorHandlerSupplier(null);

@Bean
Expand Down Expand Up @@ -293,7 +298,13 @@ public GraphQLConfiguration graphQLServletConfiguration(
GraphQLObjectMapper graphQLObjectMapper,
@Autowired(required = false) List<GraphQLServletListener> listeners,
@Autowired(required = false) BatchInputPreProcessor batchInputPreProcessor,
@Autowired(required = false) GraphQLResponseCacheManager responseCacheManager) {
@Autowired(required = false) GraphQLResponseCacheManager responseCacheManager,
@Autowired(required = false) AsyncTaskDecorator asyncTaskDecorator,
@Autowired(required = false) @Qualifier("graphqlAsyncTaskExecutor") Executor asyncExecutor) {
long asyncTimeout =
graphQLServletProperties.getAsyncTimeout() != null
? graphQLServletProperties.getAsyncTimeout()
: asyncServletProperties.getTimeout();
return GraphQLConfiguration.with(invocationInputFactory)
.with(graphQLInvoker)
.with(graphQLObjectMapper)
Expand All @@ -302,10 +313,34 @@ public GraphQLConfiguration graphQLServletConfiguration(
.with(batchInputPreProcessor)
.with(graphQLServletProperties.getContextSetting())
.with(responseCacheManager)
.asyncTimeout(graphQLServletProperties.getAsyncTimeout())
.asyncTimeout(asyncTimeout)
.with(asyncTaskDecorator)
.asyncCorePoolSize(asyncServletProperties.getThreads().getMin())
.asyncCorePoolSize(asyncServletProperties.getThreads().getMax())
.with(asyncExecutor)
.build();
}

@Bean("graphqlAsyncTaskExecutor")
@ConditionalOnMissingBean(name = "graphqlAsyncTaskExecutor")
public Executor threadPoolTaskExecutor() {
if (isAsyncModeEnabled()) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(asyncServletProperties.getThreads().getMin());
executor.setMaxPoolSize(asyncServletProperties.getThreads().getMax());
executor.setThreadNamePrefix(asyncServletProperties.getThreads().getNamePrefix());
executor.initialize();
return executor;
}
return null;
}

private boolean isAsyncModeEnabled() {
return graphQLServletProperties.getAsyncModeEnabled() != null
? graphQLServletProperties.getAsyncModeEnabled()
: asyncServletProperties.isEnabled();
}

@Bean
@ConditionalOnMissingBean
public GraphQLHttpServlet graphQLHttpServlet(GraphQLConfiguration graphQLConfiguration) {
Expand All @@ -323,7 +358,11 @@ public ServletRegistrationBean<AbstractGraphQLHttpServlet> graphQLServletRegistr
} else {
registration.setMultipartConfig(new MultipartConfigElement(""));
}
registration.setAsyncSupported(graphQLServletProperties.isAsyncModeEnabled());
if (graphQLServletProperties.getAsyncModeEnabled() != null) {
registration.setAsyncSupported(graphQLServletProperties.getAsyncModeEnabled());
} else {
registration.setAsyncSupported(asyncServletProperties.isEnabled());
}
return registration;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package graphql.kickstart.autoconfigure.web.servlet;

import graphql.kickstart.autoconfigure.web.OnSchemaOrSchemaProviderBean;
import java.util.concurrent.Executor;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor;
import org.springframework.web.servlet.DispatcherServlet;

@Configuration
@RequiredArgsConstructor
@ConditionalOnWebApplication(type = Type.SERVLET)
@Conditional(OnSchemaOrSchemaProviderBean.class)
@ConditionalOnProperty(
value = "graphql.servlet.enabled",
havingValue = "true",
matchIfMissing = true)
@AutoConfigureBefore(GraphQLWebAutoConfiguration.class)
@ConditionalOnClass({DispatcherServlet.class, DefaultAuthenticationEventPublisher.class})
@EnableConfigurationProperties({GraphQLServletProperties.class, AsyncServletProperties.class})
public class GraphQLWebSecurityAutoConfiguration {

private final GraphQLServletProperties graphqlServletProperties;
private final AsyncServletProperties asyncServletProperties;

@Bean("graphqlAsyncTaskExecutor")
@ConditionalOnMissingBean(name = "graphqlAsyncTaskExecutor")
public Executor threadPoolTaskExecutor() {
if (isAsyncModeEnabled() && asyncServletProperties.isDelegateSecurityContext()) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(asyncServletProperties.getThreads().getMin());
executor.setMaxPoolSize(asyncServletProperties.getThreads().getMax());
executor.setThreadNamePrefix(asyncServletProperties.getThreads().getNamePrefix());
executor.initialize();
return new DelegatingSecurityContextAsyncTaskExecutor(executor);
}
return null;
}

private boolean isAsyncModeEnabled() {
return graphqlServletProperties.getAsyncModeEnabled() != null
? graphqlServletProperties.getAsyncModeEnabled()
: asyncServletProperties.isEnabled();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ org.springframework.context.ApplicationContextInitializer=\
graphql.kickstart.autoconfigure.web.servlet.GraphQLExtendedScalarsInitializer
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
graphql.kickstart.autoconfigure.web.servlet.GraphQLWebAutoConfiguration,\
graphql.kickstart.autoconfigure.web.servlet.GraphQLWebSecurityAutoConfiguration,\
graphql.kickstart.autoconfigure.web.servlet.GraphQLWebsocketAutoConfiguration,\
graphql.kickstart.autoconfigure.web.servlet.GraphQLInstrumentationAutoConfiguration,\
graphql.kickstart.autoconfigure.web.reactive.GraphQLSpringWebfluxAutoConfiguration,\
Expand Down