Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ public static GraphQLEndpointConventionBuilder MapGraphQL(
var schemaNameOrDefault = schemaName ?? ISchemaDefinition.DefaultName;
var pattern = Parse(path + "/{**slug}");
var requestPipeline = endpointRouteBuilder.CreateApplicationBuilder();
var services = endpointRouteBuilder.ServiceProvider;
requestPipeline.MapGraphQL(path, schemaNameOrDefault);
var serverOptions = endpointRouteBuilder.ServiceProvider.GetRequiredService<IOptionsMonitor<GraphQLServerOptions>>().Get(schemaNameOrDefault);
var serverOptions = services.GetServerOptions(schemaNameOrDefault);

return new GraphQLEndpointConventionBuilder(
endpointRouteBuilder
Expand Down Expand Up @@ -123,19 +124,22 @@ public static IApplicationBuilder MapGraphQL(

path = path.ToString().TrimEnd('/');

var executorProvider = applicationBuilder.ApplicationServices.GetRequiredService<IRequestExecutorProvider>();
var executorEvents = applicationBuilder.ApplicationServices.GetRequiredService<IRequestExecutorEvents>();
var formOptions = applicationBuilder.ApplicationServices.GetRequiredService<IOptions<FormOptions>>();
var services = applicationBuilder.ApplicationServices;
var executorProvider = services.GetRequiredService<IRequestExecutorProvider>();
var executorEvents = services.GetRequiredService<IRequestExecutorEvents>();
var formOptions = services.GetRequiredService<IOptions<FormOptions>>();
var executor = new HttpRequestExecutorProxy(executorProvider, executorEvents, schemaName);
var serverOptions = applicationBuilder.ApplicationServices.GetRequiredService<IOptionsMonitor<GraphQLServerOptions>>().Get(schemaName);
var serverOptions = services.GetServerOptions(schemaName);

applicationBuilder
.Use(MiddlewareFactory.CreateCancellationMiddleware())
.Use(MiddlewareFactory.CreateConcurrencyGateMiddleware(serverOptions.MaxConcurrentRequests))
.Use(MiddlewareFactory.CreateWebSocketSubscriptionMiddleware(executor, serverOptions))
.Use(MiddlewareFactory.CreateHttpPostMiddleware(executor, serverOptions))
.Use(MiddlewareFactory.CreateHttpMultipartMiddleware(executor, serverOptions, formOptions))
.Use(MiddlewareFactory.CreateHttpGetMiddleware(executor, serverOptions))
.Use(MiddlewareFactory.CreateHttpGetSchemaMiddleware(executor, serverOptions, path, MiddlewareRoutingType.Integrated))
.Use(MiddlewareFactory.CreateHttpGetSchemaMiddleware(
executor, serverOptions, path, MiddlewareRoutingType.Integrated))
.UseNitroApp(path, serverOptions.Tool)
.Use(_ => context =>
{
Expand Down Expand Up @@ -203,14 +207,16 @@ public static GraphQLHttpEndpointConventionBuilder MapGraphQLHttp(
var requestPipeline = endpointRouteBuilder.CreateApplicationBuilder();
var schemaNameOrDefault = schemaName ?? ISchemaDefinition.DefaultName;

var executorProvider = endpointRouteBuilder.ServiceProvider.GetRequiredService<IRequestExecutorProvider>();
var executorEvents = endpointRouteBuilder.ServiceProvider.GetRequiredService<IRequestExecutorEvents>();
var formOptions = endpointRouteBuilder.ServiceProvider.GetRequiredService<IOptions<FormOptions>>();
var services = endpointRouteBuilder.ServiceProvider;
var executorProvider = services.GetRequiredService<IRequestExecutorProvider>();
var executorEvents = services.GetRequiredService<IRequestExecutorEvents>();
var formOptions = services.GetRequiredService<IOptions<FormOptions>>();
var executor = new HttpRequestExecutorProxy(executorProvider, executorEvents, schemaNameOrDefault);
var serverOptions = endpointRouteBuilder.ServiceProvider.GetRequiredService<IOptionsMonitor<GraphQLServerOptions>>().Get(schemaNameOrDefault);
var serverOptions = services.GetServerOptions(schemaNameOrDefault);

requestPipeline
.Use(MiddlewareFactory.CreateCancellationMiddleware())
.Use(MiddlewareFactory.CreateConcurrencyGateMiddleware(serverOptions.MaxConcurrentRequests))
.Use(MiddlewareFactory.CreateHttpPostMiddleware(executor, serverOptions))
.Use(MiddlewareFactory.CreateHttpMultipartMiddleware(executor, serverOptions, formOptions))
.Use(MiddlewareFactory.CreateHttpGetMiddleware(executor, serverOptions))
Expand Down Expand Up @@ -283,10 +289,11 @@ public static GraphQLWebSocketEndpointConventionBuilder MapGraphQLWebSocket(
var requestPipeline = endpointRouteBuilder.CreateApplicationBuilder();
var schemaNameOrDefault = schemaName ?? ISchemaDefinition.DefaultName;

var executorProvider = endpointRouteBuilder.ServiceProvider.GetRequiredService<IRequestExecutorProvider>();
var executorEvents = endpointRouteBuilder.ServiceProvider.GetRequiredService<IRequestExecutorEvents>();
var services = endpointRouteBuilder.ServiceProvider;
var executorProvider = services.GetRequiredService<IRequestExecutorProvider>();
var executorEvents = services.GetRequiredService<IRequestExecutorEvents>();
var executor = new HttpRequestExecutorProxy(executorProvider, executorEvents, schemaNameOrDefault);
var serverOptions = endpointRouteBuilder.ServiceProvider.GetRequiredService<IOptionsMonitor<GraphQLServerOptions>>().Get(schemaNameOrDefault);
var serverOptions = services.GetServerOptions(schemaNameOrDefault);

requestPipeline
.Use(MiddlewareFactory.CreateCancellationMiddleware())
Expand Down Expand Up @@ -362,14 +369,17 @@ public static IEndpointConventionBuilder MapGraphQLSchema(
var requestPipeline = endpointRouteBuilder.CreateApplicationBuilder();
var schemaNameOrDefault = schemaName ?? ISchemaDefinition.DefaultName;

var executorProvider = endpointRouteBuilder.ServiceProvider.GetRequiredService<IRequestExecutorProvider>();
var executorEvents = endpointRouteBuilder.ServiceProvider.GetRequiredService<IRequestExecutorEvents>();
var services = endpointRouteBuilder.ServiceProvider;
var executorProvider = services.GetRequiredService<IRequestExecutorProvider>();
var executorEvents = services.GetRequiredService<IRequestExecutorEvents>();
var executor = new HttpRequestExecutorProxy(executorProvider, executorEvents, schemaNameOrDefault);
var serverOptions = endpointRouteBuilder.ServiceProvider.GetRequiredService<IOptionsMonitor<GraphQLServerOptions>>().Get(schemaNameOrDefault);
var serverOptions = services.GetServerOptions(schemaNameOrDefault);

requestPipeline
.Use(MiddlewareFactory.CreateCancellationMiddleware())
.Use(MiddlewareFactory.CreateHttpGetSchemaMiddleware(executor, serverOptions, PathString.Empty, MiddlewareRoutingType.Explicit))
.Use(MiddlewareFactory.CreateConcurrencyGateMiddleware(serverOptions.MaxConcurrentRequests))
.Use(MiddlewareFactory.CreateHttpGetSchemaMiddleware(
executor, serverOptions, PathString.Empty, MiddlewareRoutingType.Explicit))
.Use(_ => context =>
{
context.Response.StatusCode = 404;
Expand Down Expand Up @@ -647,6 +657,9 @@ public static NitroAppEndpointConventionBuilder WithOptions(
return builder;
}

private static GraphQLServerOptions GetServerOptions(this IServiceProvider services, string schemaName)
=> services.GetRequiredService<IOptionsMonitor<GraphQLServerOptions>>().Get(schemaName);

private static void TryResolveSchemaName(IServiceProvider services, ref string? schemaName)
{
if (schemaName is null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,37 @@ internal static Func<RequestDelegate, RequestDelegate> CreateCancellationMiddlew
};
}

internal static Func<RequestDelegate, RequestDelegate> CreateConcurrencyGateMiddleware(
int? maxConcurrentRequests)
{
if (maxConcurrentRequests is null or <= 0)
{
return next => next;
}

var semaphore = new SemaphoreSlim(maxConcurrentRequests.Value, maxConcurrentRequests.Value);

return next => async context =>
{
if (context.WebSockets.IsWebSocketRequest)
{
await next(context);
return;
}

await semaphore.WaitAsync(context.RequestAborted);

try
{
await next(context);
}
finally
{
semaphore.Release();
}
};
}

internal static Func<RequestDelegate, RequestDelegate> CreateWebSocketSubscriptionMiddleware(
HttpRequestExecutorProxy executor,
GraphQLServerOptions serverOptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ public sealed class GraphQLServerOptions
/// </summary>
public int MaxBatchSize { get; set; } = 1024;

/// <summary>
/// Gets or sets the maximum number of concurrent GraphQL requests that can be
/// processed simultaneously. A value of <c>null</c> means unlimited. Defaults to 64.
/// </summary>
public int? MaxConcurrentRequests { get; set; } = 64;

internal GraphQLServerOptions Clone()
=> new()
{
Expand All @@ -81,6 +87,7 @@ internal GraphQLServerOptions Clone()
EnforceMultipartRequestsPreflightHeader = EnforceMultipartRequestsPreflightHeader,
EnableSchemaRequests = EnableSchemaRequests,
Batching = Batching,
MaxBatchSize = MaxBatchSize
MaxBatchSize = MaxBatchSize,
MaxConcurrentRequests = MaxConcurrentRequests
};
}
Loading