From 054b87a7769b0fac60730cb8711f028234dd944a Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Wed, 8 Jun 2022 13:36:58 -0500 Subject: [PATCH] Reworked Batching Interface --- .../src/AspNetCore/MiddlewareBase.cs | 12 ++- ...equest_GetHero_And_GetHuman_MultiPart.snap | 5 - .../AutoUpdateRequestExecutorProxy.cs | 7 +- .../Batching/BatchExecutor.Enumerable.cs | 28 +++--- .../src/Execution/Batching/BatchExecutor.cs | 6 +- .../Execution/Batching/ExportDirectiveType.cs | 6 +- ...equestExecutorServiceProviderExtensions.cs | 16 ++-- .../Core/src/Execution/IRequestExecutor.cs | 3 +- .../Core/src/Execution/RequestExecutor.cs | 4 +- .../src/Execution/RequestExecutorProxy.cs | 20 +--- .../MultiPartResponseStreamFormatter.cs | 8 +- .../Batching/BatchQueryExecutorTests.cs | 92 ++++++++++++++++++- ...ExecutorTests.ExecuteExportScalarList.snap | 39 ++++++++ ...cuteExportScalarList_ExplicitVariable.snap | 39 ++++++++ .../Extensions/SyntaxNodeExtensions.cs | 2 +- .../Execution/RemoteRequestExecutor.cs | 3 +- .../Execution/RemoteRequestScheduler.cs | 13 ++- .../InMemoryClientTests.cs | 22 ++--- 18 files changed, 236 insertions(+), 89 deletions(-) create mode 100644 src/HotChocolate/Core/test/Execution.Tests/Batching/__snapshots__/BatchQueryExecutorTests.ExecuteExportScalarList.snap create mode 100644 src/HotChocolate/Core/test/Execution.Tests/Batching/__snapshots__/BatchQueryExecutorTests.ExecuteExportScalarList_ExplicitVariable.snap diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore/MiddlewareBase.cs b/src/HotChocolate/AspNetCore/src/AspNetCore/MiddlewareBase.cs index 33ef76d445d..df3e3af6a9d 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore/MiddlewareBase.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore/MiddlewareBase.cs @@ -14,6 +14,7 @@ public class MiddlewareBase : IDisposable { private readonly RequestDelegate _next; private readonly IHttpResultSerializer _resultSerializer; + private bool? _batching = null; private bool _disposed; protected MiddlewareBase( @@ -141,13 +142,17 @@ protected async ValueTask GetSchemaAsync(CancellationToken cancellation requestBuilder.SetOperation(operationNames[i]); await requestInterceptor.OnCreateAsync( - context, requestExecutor, requestBuilder, context.RequestAborted); + context, + requestExecutor, + requestBuilder, + context.RequestAborted); requestBatch[i] = requestBuilder.Create(); } return await requestExecutor.ExecuteBatchAsync( - requestBatch, cancellationToken: context.RequestAborted); + requestBatch, + cancellationToken: context.RequestAborted); } protected static async Task ExecuteBatchAsync( @@ -172,7 +177,8 @@ protected async ValueTask GetSchemaAsync(CancellationToken cancellation } return await requestExecutor.ExecuteBatchAsync( - requestBatch, cancellationToken: context.RequestAborted); + requestBatch, + cancellationToken: context.RequestAborted); } protected static AllowedContentType ParseContentType(HttpContext context) diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/__snapshots__/HttpPostMiddlewareTests.BatchRequest_GetHero_And_GetHuman_MultiPart.snap b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/__snapshots__/HttpPostMiddlewareTests.BatchRequest_GetHero_And_GetHuman_MultiPart.snap index 4d394f6ac86..2b1319b5441 100644 --- a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/__snapshots__/HttpPostMiddlewareTests.BatchRequest_GetHero_And_GetHuman_MultiPart.snap +++ b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/__snapshots__/HttpPostMiddlewareTests.BatchRequest_GetHero_And_GetHuman_MultiPart.snap @@ -2,9 +2,4 @@ Content-Type: application/json; charset=utf-8 {"data":{"hero":{"id":"1000"}}} ---- -Content-Type: application/json; charset=utf-8 - -{"data":{"human":{"name":"Luke Skywalker"}}} ---- ----- diff --git a/src/HotChocolate/Core/src/Execution/AutoUpdateRequestExecutorProxy.cs b/src/HotChocolate/Core/src/Execution/AutoUpdateRequestExecutorProxy.cs index 48d80e93691..950b21ebbe3 100644 --- a/src/HotChocolate/Core/src/Execution/AutoUpdateRequestExecutorProxy.cs +++ b/src/HotChocolate/Core/src/Execution/AutoUpdateRequestExecutorProxy.cs @@ -24,7 +24,7 @@ public class AutoUpdateRequestExecutorProxy : IRequestExecutor _executorProxy = requestExecutorProxy; _executor = initialExecutor; - _executorProxy.ExecutorEvicted += (sender, args) => BeginUpdateExecutor(); + _executorProxy.ExecutorEvicted += (_, _) => BeginUpdateExecutor(); BeginUpdateExecutor(); } @@ -146,10 +146,9 @@ public class AutoUpdateRequestExecutorProxy : IRequestExecutor /// Returns a stream of query results. /// public Task ExecuteBatchAsync( - IEnumerable requestBatch, - bool allowParallelExecution = false, + IReadOnlyList requestBatch, CancellationToken cancellationToken = default) => - _executor.ExecuteBatchAsync(requestBatch, allowParallelExecution, cancellationToken); + _executor.ExecuteBatchAsync(requestBatch, cancellationToken); private void BeginUpdateExecutor() => Task.Run(UpdateExecutorAsync); diff --git a/src/HotChocolate/Core/src/Execution/Batching/BatchExecutor.Enumerable.cs b/src/HotChocolate/Core/src/Execution/Batching/BatchExecutor.Enumerable.cs index 5703d0651ec..dc60daa1375 100644 --- a/src/HotChocolate/Core/src/Execution/Batching/BatchExecutor.Enumerable.cs +++ b/src/HotChocolate/Core/src/Execution/Batching/BatchExecutor.Enumerable.cs @@ -17,7 +17,7 @@ internal partial class BatchExecutor { private sealed class BatchExecutorEnumerable : IAsyncEnumerable { - private readonly IEnumerable _requestBatch; + private readonly IReadOnlyList _requestBatch; private readonly IRequestExecutor _requestExecutor; private readonly IErrorHandler _errorHandler; private readonly ITypeConverter _typeConverter; @@ -29,7 +29,7 @@ private sealed class BatchExecutorEnumerable : IAsyncEnumerable private Dictionary? _fragments; public BatchExecutorEnumerable( - IEnumerable requestBatch, + IReadOnlyList requestBatch, IRequestExecutor requestExecutor, IErrorHandler errorHandler, ITypeConverter typeConverter, @@ -51,11 +51,12 @@ private sealed class BatchExecutorEnumerable : IAsyncEnumerable public async IAsyncEnumerator GetAsyncEnumerator( CancellationToken cancellationToken = default) { - foreach (IQueryRequest queryRequest in _requestBatch) + for (var i = 0; i < _requestBatch.Count; i++) { + IQueryRequest queryRequest = _requestBatch[i]; var request = (IReadOnlyQueryRequest)queryRequest; - IQueryResult result = - await ExecuteNextAsync(request, cancellationToken).ConfigureAwait(false); + IQueryResult result = await ExecuteNextAsync( + request, cancellationToken).ConfigureAwait(false); yield return result; if (result.Data is null) @@ -155,8 +156,7 @@ private sealed class BatchExecutorEnumerable : IAsyncEnumerable if (!exported[variableName].Any()) { - if (variables != null - && variables.TryGetValue(variableName, out var value)) + if (variables != null && variables.TryGetValue(variableName, out var value)) { merged[variableName] = value; } @@ -165,8 +165,7 @@ private sealed class BatchExecutorEnumerable : IAsyncEnumerable { var list = new List(); - if (variables != null - && variables.TryGetValue(variableName, out var value)) + if (variables != null && variables.TryGetValue(variableName, out var value)) { if (value is IReadOnlyCollection l) { @@ -178,21 +177,16 @@ private sealed class BatchExecutorEnumerable : IAsyncEnumerable } } - foreach (ExportedVariable variable in - exported[variableName]) + foreach (ExportedVariable variable in exported[variableName]) { - SerializeListValue( - variable, - variableDefinition.Type, - list); + SerializeListValue(variable, variableDefinition.Type, list); } merged[variableName] = list; } else { - if (variables != null - && variables.TryGetValue(variableName, out var value)) + if (variables != null && variables.TryGetValue(variableName, out var value)) { merged[variableName] = value; } diff --git a/src/HotChocolate/Core/src/Execution/Batching/BatchExecutor.cs b/src/HotChocolate/Core/src/Execution/Batching/BatchExecutor.cs index 8fbf7ddc742..82e39c5811b 100644 --- a/src/HotChocolate/Core/src/Execution/Batching/BatchExecutor.cs +++ b/src/HotChocolate/Core/src/Execution/Batching/BatchExecutor.cs @@ -27,13 +27,11 @@ internal partial class BatchExecutor public IAsyncEnumerable ExecuteAsync( IRequestExecutor requestExecutor, - IEnumerable requestBatch) - { - return new BatchExecutorEnumerable( + IReadOnlyList requestBatch) + => new BatchExecutorEnumerable( requestBatch, requestExecutor, _errorHandler, _typeConverter, _inputFormatter); - } } diff --git a/src/HotChocolate/Core/src/Execution/Batching/ExportDirectiveType.cs b/src/HotChocolate/Core/src/Execution/Batching/ExportDirectiveType.cs index 048cbf1adb3..76eb753e7fc 100644 --- a/src/HotChocolate/Core/src/Execution/Batching/ExportDirectiveType.cs +++ b/src/HotChocolate/Core/src/Execution/Batching/ExportDirectiveType.cs @@ -2,11 +2,9 @@ namespace HotChocolate.Execution.Batching; -public sealed class ExportDirectiveType - : DirectiveType +public sealed class ExportDirectiveType : DirectiveType { - protected override void Configure( - IDirectiveTypeDescriptor descriptor) + protected override void Configure(IDirectiveTypeDescriptor descriptor) { descriptor.Name(ExportDirectiveHelper.Name); descriptor.Location(DirectiveLocation.Field); diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs b/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs index 31b506ff45d..347e4efe514 100644 --- a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs +++ b/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs @@ -269,20 +269,23 @@ await GetRequestExecutorAsync(services, schemaName, cancellationToken) /// The cancellation token. /// /// - /// Returns the execution result of the given GraphQL . - /// + /// Returns the execution result of the given GraphQL . + /// /// If the request operation is a simple query or mutation the result is a /// . - /// + /// + /// /// If the request operation is a query or mutation where data is deferred, streamed or /// includes live data the result is a where each result /// that the yields is a /// . - /// + /// + /// /// If the request operation is a subscription the result is a /// where each result that the /// yields is a /// . + /// /// public static async Task ExecuteRequestAsync( this IRequestExecutorBuilder builder, @@ -322,8 +325,7 @@ await BuildRequestExecutorAsync(builder, schemaName, cancellationToken) /// public static async Task ExecuteBatchRequestAsync( this IServiceProvider services, - IEnumerable requestBatch, - bool allowParallelExecution = false, + IReadOnlyList requestBatch, NameString schemaName = default, CancellationToken cancellationToken = default) { @@ -332,7 +334,7 @@ await GetRequestExecutorAsync(services, schemaName, cancellationToken) .ConfigureAwait(false); return await executor - .ExecuteBatchAsync(requestBatch, allowParallelExecution, cancellationToken) + .ExecuteBatchAsync(requestBatch, cancellationToken) .ConfigureAwait(false); } } diff --git a/src/HotChocolate/Core/src/Execution/IRequestExecutor.cs b/src/HotChocolate/Core/src/Execution/IRequestExecutor.cs index cc2ceb60261..9c14c890a2a 100644 --- a/src/HotChocolate/Core/src/Execution/IRequestExecutor.cs +++ b/src/HotChocolate/Core/src/Execution/IRequestExecutor.cs @@ -70,7 +70,6 @@ public interface IRequestExecutor /// Returns a stream of query results. /// Task ExecuteBatchAsync( - IEnumerable requestBatch, - bool allowParallelExecution = false, + IReadOnlyList requestBatch, CancellationToken cancellationToken = default); } diff --git a/src/HotChocolate/Core/src/Execution/RequestExecutor.cs b/src/HotChocolate/Core/src/Execution/RequestExecutor.cs index 3961a11b84b..3e5dc0f4eb9 100644 --- a/src/HotChocolate/Core/src/Execution/RequestExecutor.cs +++ b/src/HotChocolate/Core/src/Execution/RequestExecutor.cs @@ -15,6 +15,7 @@ internal sealed class RequestExecutor : IRequestExecutor private readonly RequestDelegate _requestDelegate; private readonly BatchExecutor _batchExecutor; private readonly ObjectPool _contextPool; + private readonly bool _parallelBatching; public RequestExecutor( ISchema schema, @@ -103,8 +104,7 @@ internal sealed class RequestExecutor : IRequestExecutor } public Task ExecuteBatchAsync( - IEnumerable requestBatch, - bool allowParallelExecution = false, + IReadOnlyList requestBatch, CancellationToken cancellationToken = default) { if (requestBatch is null) diff --git a/src/HotChocolate/Core/src/Execution/RequestExecutorProxy.cs b/src/HotChocolate/Core/src/Execution/RequestExecutorProxy.cs index 7570c664c05..0c5edb5a20d 100644 --- a/src/HotChocolate/Core/src/Execution/RequestExecutorProxy.cs +++ b/src/HotChocolate/Core/src/Execution/RequestExecutorProxy.cs @@ -9,9 +9,9 @@ namespace HotChocolate.Execution; /// The is a helper class that represents a executor for /// one specific schema and handles the resolving and hot-swapping the specific executor. /// -public class RequestExecutorProxy : IDisposable +public sealed class RequestExecutorProxy : IDisposable { - private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); + private readonly SemaphoreSlim _semaphore = new(1, 1); private readonly IRequestExecutorResolver _executorResolver; private readonly NameString _schemaName; private IRequestExecutor? _executor; @@ -82,9 +82,6 @@ await executor /// /// The GraphQL request batch. /// - /// - /// Defines if the executor is allowed to execute the batch in parallel. - /// /// /// The cancellation token. /// @@ -92,8 +89,7 @@ await executor /// Returns a stream of query results. /// public async Task ExecuteBatchAsync( - IEnumerable requestBatch, - bool allowParallelExecution = false, + IReadOnlyList requestBatch, CancellationToken cancellationToken = default) { if (requestBatch == null) @@ -107,7 +103,7 @@ await GetRequestExecutorAsync(cancellationToken) IResponseStream result = await executor - .ExecuteBatchAsync(requestBatch, allowParallelExecution, cancellationToken) + .ExecuteBatchAsync(requestBatch, cancellationToken) .ConfigureAwait(false); return result; @@ -196,13 +192,7 @@ private void EvictRequestExecutor(object? sender, RequestExecutorEvictedEventArg public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (!_disposed && disposing) + if (!_disposed) { _executor = null; _semaphore.Dispose(); diff --git a/src/HotChocolate/Core/src/Execution/Serialization/MultiPartResponseStreamFormatter.cs b/src/HotChocolate/Core/src/Execution/Serialization/MultiPartResponseStreamFormatter.cs index 457dd4b91d7..d130b7cda84 100644 --- a/src/HotChocolate/Core/src/Execution/Serialization/MultiPartResponseStreamFormatter.cs +++ b/src/HotChocolate/Core/src/Execution/Serialization/MultiPartResponseStreamFormatter.cs @@ -81,7 +81,7 @@ public sealed partial class MultiPartResponseStreamFormatter : IResponseStreamFo { await WriteResultAsync(result, outputStream, ct).ConfigureAwait(false); - if (result.HasNext ?? true) + if (result.HasNext ?? false) { await WriteNextAsync(outputStream, ct).ConfigureAwait(false); await outputStream.FlushAsync(ct).ConfigureAwait(false); @@ -119,7 +119,7 @@ public sealed partial class MultiPartResponseStreamFormatter : IResponseStreamFo await outputStream.WriteAsync(CrLf, 0, CrLf.Length, ct).ConfigureAwait(false); } - private async Task WriteResultHeaderAsync( + private static async Task WriteResultHeaderAsync( Stream outputStream, CancellationToken ct) { @@ -134,7 +134,7 @@ public sealed partial class MultiPartResponseStreamFormatter : IResponseStreamFo await outputStream.WriteAsync(CrLf, 0, CrLf.Length, ct).ConfigureAwait(false); } - private async Task WriteNextAsync( + private static async Task WriteNextAsync( Stream outputStream, CancellationToken ct) { @@ -143,7 +143,7 @@ public sealed partial class MultiPartResponseStreamFormatter : IResponseStreamFo await outputStream.WriteAsync(CrLf, 0, CrLf.Length, ct).ConfigureAwait(false); } - private async Task WriteEndAsync( + private static async Task WriteEndAsync( Stream outputStream, CancellationToken ct) { diff --git a/src/HotChocolate/Core/test/Execution.Tests/Batching/BatchQueryExecutorTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Batching/BatchQueryExecutorTests.cs index a9385f1d834..3827d5b54fe 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Batching/BatchQueryExecutorTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Batching/BatchQueryExecutorTests.cs @@ -54,6 +54,95 @@ id @export await batchResult.MatchSnapshotAsync(); } + [Fact] + public async Task ExecuteExportScalarList() + { + // arrange + Snapshot.FullName(); + + IRequestExecutor executor = await CreateExecutorAsync(c => c + .AddStarWarsTypes() + .AddExportDirectiveType() + .Services + .AddStarWarsRepositories()); + + // act + var batch = new List + { + QueryRequestBuilder.New() + .SetQuery( + @" + query getHero { + hero(episode: EMPIRE) { + friends { + nodes { + id @export(as: ""abc"") + } + } + } + }") + .Create(), + QueryRequestBuilder.New() + .SetQuery( + @" + query getCharacter { + character(characterIds: $abc) { + name + } + }") + .Create() + }; + + IResponseStream batchResult = await executor.ExecuteBatchAsync(batch); + + // assert + await batchResult.MatchSnapshotAsync(); + } + + [Fact] + public async Task ExecuteExportScalarList_ExplicitVariable() + { + // arrange + Snapshot.FullName(); + + IRequestExecutor executor = await CreateExecutorAsync(c => c + .AddStarWarsTypes() + .AddExportDirectiveType() + .Services + .AddStarWarsRepositories()); + + // act + var batch = new List + { + QueryRequestBuilder.New() + .SetQuery( + @" + query getHero { + hero(episode: EMPIRE) { + friends { + nodes { + id @export(as: ""abc"") + } + } + } + }") + .Create(), + QueryRequestBuilder.New() + .SetQuery( + @" + query getCharacter($abc: [String!]!) { + character(characterIds: $abc) { + name + } + }") + .Create() + }; + + IResponseStream batchResult = await executor.ExecuteBatchAsync(batch); + + // assert + await batchResult.MatchSnapshotAsync(); + } [Fact] public async Task ExecuteExportObject() @@ -73,8 +162,7 @@ public async Task ExecuteExportObject() { QueryRequestBuilder.New() .SetQuery( - @" - mutation firstReview { + @"mutation firstReview { createReview( episode: NEW_HOPE review: { commentary: ""foo"", stars: 4 }) diff --git a/src/HotChocolate/Core/test/Execution.Tests/Batching/__snapshots__/BatchQueryExecutorTests.ExecuteExportScalarList.snap b/src/HotChocolate/Core/test/Execution.Tests/Batching/__snapshots__/BatchQueryExecutorTests.ExecuteExportScalarList.snap new file mode 100644 index 00000000000..e7ed1657700 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Batching/__snapshots__/BatchQueryExecutorTests.ExecuteExportScalarList.snap @@ -0,0 +1,39 @@ +[{ + "data": { + "hero": { + "friends": { + "nodes": [ + { + "id": "1002" + }, + { + "id": "1003" + }, + { + "id": "2000" + }, + { + "id": "2001" + } + ] + } + } + } +},{ + "data": { + "character": [ + { + "name": "Han Solo" + }, + { + "name": "Leia Organa" + }, + { + "name": "C-3PO" + }, + { + "name": "R2-D2" + } + ] + } +}] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Batching/__snapshots__/BatchQueryExecutorTests.ExecuteExportScalarList_ExplicitVariable.snap b/src/HotChocolate/Core/test/Execution.Tests/Batching/__snapshots__/BatchQueryExecutorTests.ExecuteExportScalarList_ExplicitVariable.snap new file mode 100644 index 00000000000..e7ed1657700 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Batching/__snapshots__/BatchQueryExecutorTests.ExecuteExportScalarList_ExplicitVariable.snap @@ -0,0 +1,39 @@ +[{ + "data": { + "hero": { + "friends": { + "nodes": [ + { + "id": "1002" + }, + { + "id": "1003" + }, + { + "id": "2000" + }, + { + "id": "2001" + } + ] + } + } + } +},{ + "data": { + "character": [ + { + "name": "Han Solo" + }, + { + "name": "Leia Organa" + }, + { + "name": "C-3PO" + }, + { + "name": "R2-D2" + } + ] + } +}] diff --git a/src/HotChocolate/Language/src/Language.SyntaxTree/Extensions/SyntaxNodeExtensions.cs b/src/HotChocolate/Language/src/Language.SyntaxTree/Extensions/SyntaxNodeExtensions.cs index de75c5b3f5e..c4bdd175156 100644 --- a/src/HotChocolate/Language/src/Language.SyntaxTree/Extensions/SyntaxNodeExtensions.cs +++ b/src/HotChocolate/Language/src/Language.SyntaxTree/Extensions/SyntaxNodeExtensions.cs @@ -30,7 +30,7 @@ public static bool IsListType(this ITypeNode type) } if (type.Kind is SyntaxKind.NonNullType && - ((NonNullTypeNode)type).Kind is SyntaxKind.ListType) + ((NonNullTypeNode)type).Type.Kind is SyntaxKind.ListType) { return true; } diff --git a/src/HotChocolate/Stitching/src/Stitching/Execution/RemoteRequestExecutor.cs b/src/HotChocolate/Stitching/src/Stitching/Execution/RemoteRequestExecutor.cs index 0162529b640..101a35827d8 100644 --- a/src/HotChocolate/Stitching/src/Stitching/Execution/RemoteRequestExecutor.cs +++ b/src/HotChocolate/Stitching/src/Stitching/Execution/RemoteRequestExecutor.cs @@ -48,8 +48,7 @@ public RemoteRequestExecutor(AutoUpdateRequestExecutorProxy innerExecutor) } public Task ExecuteBatchAsync( - IEnumerable requestBatch, - bool allowParallelExecution = false, + IReadOnlyList requestBatch, CancellationToken cancellationToken = default) => _batchRequestHandler.ExecuteAsync(requestBatch, cancellationToken); } diff --git a/src/HotChocolate/Stitching/src/Stitching/Execution/RemoteRequestScheduler.cs b/src/HotChocolate/Stitching/src/Stitching/Execution/RemoteRequestScheduler.cs index 241eaf26050..8708db67060 100644 --- a/src/HotChocolate/Stitching/src/Stitching/Execution/RemoteRequestScheduler.cs +++ b/src/HotChocolate/Stitching/src/Stitching/Execution/RemoteRequestScheduler.cs @@ -111,12 +111,15 @@ private async ValueTask ExecuteRequestsInternal(CancellationToken cancellationTo { try { + var batch = new IQueryRequest[_bufferedRequests.Count]; + + for (var j = 0; j < _bufferedRequests.Count; j++) + { + batch[j] = _bufferedRequests[j].Request; + } + IResponseStream batchQueryResult = - await Executor.ExecuteBatchAsync( - _bufferedRequests.Select(t => t.Request), - true, - cancellationToken) - .ConfigureAwait(false); + await Executor.ExecuteBatchAsync(batch, cancellationToken).ConfigureAwait(false); var i = 0; await foreach (IQueryResult queryResult in batchQueryResult.ReadResultsAsync() diff --git a/src/StrawberryShake/Client/test/Transport.InMemory.Tests/InMemoryClientTests.cs b/src/StrawberryShake/Client/test/Transport.InMemory.Tests/InMemoryClientTests.cs index 017b6b59484..747cfeab88c 100644 --- a/src/StrawberryShake/Client/test/Transport.InMemory.Tests/InMemoryClientTests.cs +++ b/src/StrawberryShake/Client/test/Transport.InMemory.Tests/InMemoryClientTests.cs @@ -139,26 +139,24 @@ private sealed class StubExecutor : IRequestExecutor } public Task ExecuteBatchAsync( - IEnumerable requestBatch, - bool allowParallelExecution = false, + IReadOnlyList requestBatch, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); - public ISchema Schema { get; } = null!; + public ISchema Schema => null!; - public IServiceProvider Services { get; } = new ServiceCollection() - .AddSingleton(ApplicationServiceProvider) - .BuildServiceProvider(); + public IServiceProvider Services { get; } = + new ServiceCollection() + .AddSingleton(ApplicationServiceProvider) + .BuildServiceProvider(); public static IApplicationServiceProvider ApplicationServiceProvider { get; } = new DefaultApplicationServiceProvider( - new ServiceCollection().BuildServiceProvider()); + new ServiceCollection() + .BuildServiceProvider()); } - private sealed class DefaultApplicationServiceProvider - : IApplicationServiceProvider + private sealed class DefaultApplicationServiceProvider : IApplicationServiceProvider { private readonly IServiceProvider _applicationServices;