Skip to content

Commit 2ad60cb

Browse files
Scope OperationCache to RequestExecutor (#8055)
Co-authored-by: Michael Staib <michael@chillicream.com>
1 parent d1c0a6f commit 2ad60cb

File tree

8 files changed

+87
-22
lines changed

8 files changed

+87
-22
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace HotChocolate.Execution.Caching;
2+
3+
internal sealed class PreparedOperationCacheOptions
4+
{
5+
public int Capacity { get; set; } = 100;
6+
}

src/HotChocolate/Core/src/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ internal static IServiceCollection TryAddDefaultCaches(
166166
{
167167
services.TryAddSingleton<IDocumentCache>(
168168
_ => new DefaultDocumentCache());
169-
services.TryAddSingleton<IPreparedOperationCache>(
170-
_ => new DefaultPreparedOperationCache());
169+
services.TryAddSingleton<PreparedOperationCacheOptions>(
170+
_ => new PreparedOperationCacheOptions { Capacity = 100 });
171171
return services;
172172
}
173173

src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,6 @@ private static IRequestExecutorBuilder CreateBuilder(
163163

164164
builder.Services.AddValidation(schemaName);
165165

166-
builder.Configure(
167-
(sp, e) =>
168-
{
169-
e.OnRequestExecutorEvictedHooks.Add(
170-
// when ever we evict this schema we will clear the caches.
171-
new OnRequestExecutorEvictedAction(
172-
_ => sp.GetRequiredService<IPreparedOperationCache>().Clear()));
173-
});
174-
175166
builder.TryAddNoOpTransactionScopeHandler();
176167
builder.TryAddTypeInterceptor<DataLoaderRootFieldTypeInterceptor>();
177168
builder.TryAddTypeInterceptor<RequirementsTypeInterceptor>();
@@ -193,11 +184,9 @@ public static IServiceCollection AddOperationCache(
193184
this IServiceCollection services,
194185
int capacity = 100)
195186
{
196-
services.RemoveAll<IPreparedOperationCache>();
197-
198-
services.AddSingleton<IPreparedOperationCache>(
199-
_ => new DefaultPreparedOperationCache(capacity));
200-
187+
services.RemoveAll<PreparedOperationCacheOptions>();
188+
services.AddSingleton<PreparedOperationCacheOptions>(
189+
_ => new PreparedOperationCacheOptions{ Capacity = capacity });
201190
return services;
202191
}
203192

src/HotChocolate/Core/src/Execution/Pipeline/OperationCacheMiddleware.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ internal sealed class OperationCacheMiddleware
1010
private readonly IExecutionDiagnosticEvents _diagnosticEvents;
1111
private readonly IPreparedOperationCache _operationCache;
1212

13-
private OperationCacheMiddleware(RequestDelegate next,
13+
private OperationCacheMiddleware(
14+
RequestDelegate next,
1415
[SchemaService] IExecutionDiagnosticEvents diagnosticEvents,
15-
IPreparedOperationCache operationCache)
16+
[SchemaService] IPreparedOperationCache operationCache)
1617
{
1718
_next = next ??
1819
throw new ArgumentNullException(nameof(next));
@@ -64,7 +65,7 @@ public static RequestCoreMiddleware Create()
6465
=> (core, next) =>
6566
{
6667
var diagnosticEvents = core.SchemaServices.GetRequiredService<IExecutionDiagnosticEvents>();
67-
var cache = core.Services.GetRequiredService<IPreparedOperationCache>();
68+
var cache = core.SchemaServices.GetRequiredService<IPreparedOperationCache>();
6869
var middleware = new OperationCacheMiddleware(next, diagnosticEvents, cache);
6970
return context => middleware.InvokeAsync(context);
7071
};

src/HotChocolate/Core/src/Execution/RequestExecutorResolver.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Reflection.Metadata;
44
using HotChocolate.Configuration;
55
using HotChocolate.Execution;
6+
using HotChocolate.Execution.Caching;
67
using HotChocolate.Execution.Configuration;
78
using HotChocolate.Execution.Errors;
89
using HotChocolate.Execution.Instrumentation;
@@ -237,6 +238,10 @@ await typeModuleChangeMonitor.ConfigureAsync(context, cancellationToken)
237238
serviceCollection.AddSingleton<IPersistedOperationOptionsAccessor>(
238239
static s => s.GetRequiredService<RequestExecutorOptions>());
239240

241+
serviceCollection.AddSingleton<IPreparedOperationCache>(
242+
_ => new DefaultPreparedOperationCache(
243+
_applicationServices.GetRequiredService<PreparedOperationCacheOptions>().Capacity));
244+
240245
serviceCollection.AddSingleton<IErrorHandler, DefaultErrorHandler>();
241246

242247
serviceCollection.TryAddDiagnosticEvents();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using HotChocolate.Execution.Caching;
2+
using HotChocolate.Types;
3+
using Microsoft.Extensions.DependencyInjection;
4+
5+
namespace HotChocolate.Execution;
6+
7+
public class PreparedOperationCacheTests
8+
{
9+
[Fact]
10+
public async Task Operation_Cache_Should_Have_Configured_Capacity()
11+
{
12+
// arrange
13+
var operationCacheCapacity = 517;
14+
var services = new ServiceCollection();
15+
services.AddOperationCache(operationCacheCapacity);
16+
services
17+
.AddGraphQL()
18+
.AddQueryType(d => d.Field("foo").Resolve(""));
19+
var provider = services.BuildServiceProvider();
20+
var resolver = provider.GetRequiredService<IRequestExecutorResolver>();
21+
22+
// act
23+
var executor = await resolver.GetRequestExecutorAsync();
24+
var operationCache = executor.Services.GetCombinedServices()
25+
.GetRequiredService<IPreparedOperationCache>();
26+
27+
// assert
28+
Assert.Equal(operationCache.Capacity, operationCacheCapacity);
29+
}
30+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using HotChocolate.Execution.Caching;
2+
using HotChocolate.Types;
3+
using Microsoft.Extensions.DependencyInjection;
4+
5+
namespace HotChocolate.Execution;
6+
7+
public class RequestExecutorResolverTests
8+
{
9+
[Fact]
10+
public async Task Operation_Cache_Should_Be_Scoped_To_Executor()
11+
{
12+
// arrange
13+
var services = new ServiceCollection();
14+
services
15+
.AddGraphQL()
16+
.AddQueryType(d => d.Field("foo").Resolve(""));
17+
var provider = services.BuildServiceProvider();
18+
var resolver = provider.GetRequiredService<IRequestExecutorResolver>();
19+
20+
// act
21+
var firstExecutor = await resolver.GetRequestExecutorAsync();
22+
var firstOperationCache = firstExecutor.Services.GetCombinedServices()
23+
.GetRequiredService<IPreparedOperationCache>();
24+
25+
resolver.EvictRequestExecutor();
26+
27+
var secondExecutor = await resolver.GetRequestExecutorAsync();
28+
var secondOperationCache = secondExecutor.Services.GetCombinedServices()
29+
.GetRequiredService<IPreparedOperationCache>();
30+
31+
// assert
32+
Assert.NotEqual(secondOperationCache, firstOperationCache);
33+
}
34+
}

src/HotChocolate/Core/test/Execution.Tests/WarmupRequestTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public async Task Warmup_Request_Warms_Up_Caches()
3434
// assert 1
3535
Assert.IsType<WarmupExecutionResult>(warmupResult);
3636

37-
var provider = executor.Services.GetCombinedServices();
38-
var documentCache = provider.GetRequiredService<IDocumentCache>();
39-
var operationCache = provider.GetRequiredService<IPreparedOperationCache>();
37+
var documentCache = executor.Services.GetCombinedServices()
38+
.GetRequiredService<IDocumentCache>();
39+
var operationCache = executor.Services.GetRequiredService<IPreparedOperationCache>();
4040

4141
Assert.True(documentCache.TryGetDocument(documentId, out _));
4242
Assert.Equal(1, operationCache.Count);

0 commit comments

Comments
 (0)