Skip to content

Commit a44d4a3

Browse files
authored
Implement incoming grain call filters for observers (#9054)
1 parent 6ff7edc commit a44d4a3

File tree

12 files changed

+556
-77
lines changed

12 files changed

+556
-77
lines changed

src/Orleans.Core/Core/ClientBuilderExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ public static IClientBuilder AddActivityPropagation(this IClientBuilder builder)
127127
builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
128128

129129
return builder
130-
.AddOutgoingGrainCallFilter<ActivityPropagationOutgoingGrainCallFilter>();
130+
.AddOutgoingGrainCallFilter<ActivityPropagationOutgoingGrainCallFilter>()
131+
.AddIncomingGrainCallFilter<ActivityPropagationIncomingGrainCallFilter>();
131132
}
132133

133134
/// <summary>
Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,75 @@
1-
namespace Orleans.Hosting
1+
namespace Orleans.Hosting;
2+
3+
/// <summary>
4+
/// Extensions for configuring grain call filters.
5+
/// </summary>
6+
public static class ClientBuilderGrainCallFilterExtensions
27
{
38
/// <summary>
4-
/// Extensions for configuring grain call filters.
9+
/// Adds an <see cref="IIncomingGrainCallFilter"/> to the filter pipeline.
10+
/// </summary>
11+
/// <param name="builder">The builder.</param>
12+
/// <param name="filter">The filter.</param>
13+
/// <returns>The builder.</returns>
14+
public static IClientBuilder AddIncomingGrainCallFilter(this IClientBuilder builder, IIncomingGrainCallFilter filter)
15+
{
16+
return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter(filter));
17+
}
18+
19+
/// <summary>
20+
/// Adds an <see cref="IIncomingGrainCallFilter"/> to the filter pipeline.
21+
/// </summary>
22+
/// <typeparam name="TImplementation">The filter implementation type.</typeparam>
23+
/// <param name="builder">The builder.</param>
24+
/// <returns>The builder.</returns>
25+
public static IClientBuilder AddIncomingGrainCallFilter<TImplementation>(this IClientBuilder builder)
26+
where TImplementation : class, IIncomingGrainCallFilter
27+
{
28+
return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter<TImplementation>());
29+
}
30+
31+
/// <summary>
32+
/// Adds an <see cref="IIncomingGrainCallFilter"/> to the filter pipeline via a delegate.
33+
/// </summary>
34+
/// <param name="builder">The builder.</param>
35+
/// <param name="filter">The filter.</param>
36+
/// <returns>The builder.</returns>
37+
public static IClientBuilder AddIncomingGrainCallFilter(this IClientBuilder builder, IncomingGrainCallFilterDelegate filter)
38+
{
39+
return builder.ConfigureServices(services => services.AddIncomingGrainCallFilter(filter));
40+
}
41+
42+
/// <summary>
43+
/// Adds an <see cref="IOutgoingGrainCallFilter"/> to the filter pipeline.
544
/// </summary>
6-
public static class ClientBuilderGrainCallFilterExtensions
45+
/// <param name="builder">The builder.</param>
46+
/// <param name="filter">The filter.</param>
47+
/// <returns>The <see cref="IClientBuilder"/>.</returns>
48+
public static IClientBuilder AddOutgoingGrainCallFilter(this IClientBuilder builder, IOutgoingGrainCallFilter filter)
749
{
8-
/// <summary>
9-
/// Adds an <see cref="IOutgoingGrainCallFilter"/> to the filter pipeline.
10-
/// </summary>
11-
/// <param name="builder">The builder.</param>
12-
/// <param name="filter">The filter.</param>
13-
/// <returns>The <see cref="IClientBuilder"/>.</returns>
14-
public static IClientBuilder AddOutgoingGrainCallFilter(this IClientBuilder builder, IOutgoingGrainCallFilter filter)
15-
{
16-
return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter(filter));
17-
}
50+
return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter(filter));
51+
}
1852

19-
/// <summary>
20-
/// Adds an <see cref="IOutgoingGrainCallFilter"/> to the filter pipeline.
21-
/// </summary>
22-
/// <typeparam name="TImplementation">The filter implementation type.</typeparam>
23-
/// <param name="builder">The builder.</param>
24-
/// <returns>The <see cref="IClientBuilder"/>.</returns>
25-
public static IClientBuilder AddOutgoingGrainCallFilter<TImplementation>(this IClientBuilder builder)
26-
where TImplementation : class, IOutgoingGrainCallFilter
27-
{
28-
return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter<TImplementation>());
29-
}
53+
/// <summary>
54+
/// Adds an <see cref="IOutgoingGrainCallFilter"/> to the filter pipeline.
55+
/// </summary>
56+
/// <typeparam name="TImplementation">The filter implementation type.</typeparam>
57+
/// <param name="builder">The builder.</param>
58+
/// <returns>The <see cref="IClientBuilder"/>.</returns>
59+
public static IClientBuilder AddOutgoingGrainCallFilter<TImplementation>(this IClientBuilder builder)
60+
where TImplementation : class, IOutgoingGrainCallFilter
61+
{
62+
return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter<TImplementation>());
63+
}
3064

31-
/// <summary>
32-
/// Adds an <see cref="IOutgoingGrainCallFilter"/> to the filter pipeline via a delegate.
33-
/// </summary>
34-
/// <param name="builder">The builder.</param>
35-
/// <param name="filter">The filter.</param>
36-
/// <returns>The <see cref="IClientBuilder"/>.</returns>
37-
public static IClientBuilder AddOutgoingGrainCallFilter(this IClientBuilder builder, OutgoingGrainCallFilterDelegate filter)
38-
{
39-
return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter(filter));
40-
}
65+
/// <summary>
66+
/// Adds an <see cref="IOutgoingGrainCallFilter"/> to the filter pipeline via a delegate.
67+
/// </summary>
68+
/// <param name="builder">The builder.</param>
69+
/// <param name="filter">The filter.</param>
70+
/// <returns>The <see cref="IClientBuilder"/>.</returns>
71+
public static IClientBuilder AddOutgoingGrainCallFilter(this IClientBuilder builder, OutgoingGrainCallFilterDelegate filter)
72+
{
73+
return builder.ConfigureServices(services => services.AddOutgoingGrainCallFilter(filter));
4174
}
4275
}

src/Orleans.Core/Core/DefaultClientServices.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public static void AddDefaultServices(IClientBuilder builder)
7373
services.TryAddSingleton<GrainBindingsResolver>();
7474
services.TryAddSingleton<LocalClientDetails>();
7575
services.TryAddSingleton<OutsideRuntimeClient>();
76+
services.TryAddSingleton<InterfaceToImplementationMappingCache>();
7677
services.TryAddSingleton<ClientGrainContext>();
7778
services.AddFromExisting<IGrainContextAccessor, ClientGrainContext>();
7879
services.TryAddFromExisting<IRuntimeClient, OutsideRuntimeClient>();

src/Orleans.Core/Runtime/InvokableObjectManager.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Threading;
55
using System.Threading.Tasks;
6+
using Microsoft.Extensions.DependencyInjection;
67
using Microsoft.Extensions.Logging;
78
using Orleans.Runtime;
89
using Orleans.Serialization;
@@ -14,23 +15,34 @@ internal class InvokableObjectManager : IDisposable
1415
{
1516
private readonly CancellationTokenSource disposed = new CancellationTokenSource();
1617
private readonly ConcurrentDictionary<ObserverGrainId, LocalObjectData> localObjects = new ConcurrentDictionary<ObserverGrainId, LocalObjectData>();
18+
19+
private readonly InterfaceToImplementationMappingCache _interfaceToImplementationMapping;
1720
private readonly IGrainContext rootGrainContext;
1821
private readonly IRuntimeClient runtimeClient;
1922
private readonly ILogger logger;
2023
private readonly DeepCopier deepCopier;
24+
private readonly DeepCopier<Response> _responseCopier;
2125
private readonly MessagingTrace messagingTrace;
26+
private List<IIncomingGrainCallFilter> _grainCallFilters;
27+
28+
private List<IIncomingGrainCallFilter> GrainCallFilters
29+
=> _grainCallFilters ??= new List<IIncomingGrainCallFilter>(runtimeClient.ServiceProvider.GetServices<IIncomingGrainCallFilter>());
2230

2331
public InvokableObjectManager(
2432
IGrainContext rootGrainContext,
2533
IRuntimeClient runtimeClient,
2634
DeepCopier deepCopier,
2735
MessagingTrace messagingTrace,
36+
DeepCopier<Response> responseCopier,
37+
InterfaceToImplementationMappingCache interfaceToImplementationMapping,
2838
ILogger logger)
2939
{
3040
this.rootGrainContext = rootGrainContext;
3141
this.runtimeClient = runtimeClient;
3242
this.deepCopier = deepCopier;
3343
this.messagingTrace = messagingTrace;
44+
_responseCopier = responseCopier;
45+
_interfaceToImplementationMapping = interfaceToImplementationMapping;
3446
this.logger = logger;
3547
}
3648

@@ -246,7 +258,20 @@ private async Task LocalObjectMessagePumpAsync()
246258
try
247259
{
248260
request.SetTarget(this);
249-
var response = await request.Invoke();
261+
var filters = _manager.GrainCallFilters;
262+
Response response;
263+
if (filters is { Count: > 0 } || LocalObject is IIncomingGrainCallFilter)
264+
{
265+
var invoker = new GrainMethodInvoker(message, this, request, filters, _manager._interfaceToImplementationMapping, _manager._responseCopier);
266+
await invoker.Invoke();
267+
response = invoker.Response;
268+
}
269+
else
270+
{
271+
response = await request.Invoke();
272+
response = _manager._responseCopier.Copy(response);
273+
}
274+
250275
if (message.Direction != Message.Directions.OneWay)
251276
{
252277
this.SendResponseAsync(message, response);

src/Orleans.Core/Runtime/OutsideRuntimeClient.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Orleans.Runtime;
1414
using Orleans.Serialization;
1515
using Orleans.Serialization.Invocation;
16+
using Orleans.Serialization.Serializers;
1617
using static Orleans.Internal.StandardExtensions;
1718

1819
namespace Orleans
@@ -30,6 +31,7 @@ internal class OutsideRuntimeClient : IRuntimeClient, IDisposable, IClusterConne
3031
private bool disposed;
3132

3233
private readonly MessagingTrace messagingTrace;
34+
private readonly InterfaceToImplementationMappingCache _interfaceToImplementationMapping;
3335

3436
public IInternalGrainFactory InternalGrainFactory { get; private set; }
3537

@@ -65,9 +67,11 @@ public OutsideRuntimeClient(
6567
IOptions<ClientMessagingOptions> clientMessagingOptions,
6668
MessagingTrace messagingTrace,
6769
IServiceProvider serviceProvider,
68-
TimeProvider timeProvider)
70+
TimeProvider timeProvider,
71+
InterfaceToImplementationMappingCache interfaceToImplementationMapping)
6972
{
7073
TimeProvider = timeProvider;
74+
_interfaceToImplementationMapping = interfaceToImplementationMapping;
7175
this.ServiceProvider = serviceProvider;
7276
_localClientDetails = localClientDetails;
7377
this.loggerFactory = loggerFactory;
@@ -105,14 +109,14 @@ internal void ConsumeServices()
105109

106110
this.InternalGrainFactory = this.ServiceProvider.GetRequiredService<IInternalGrainFactory>();
107111
this.messageFactory = this.ServiceProvider.GetService<MessageFactory>();
108-
109-
var copier = this.ServiceProvider.GetRequiredService<DeepCopier>();
110112
this.localObjects = new InvokableObjectManager(
111113
ServiceProvider.GetRequiredService<ClientGrainContext>(),
112114
this,
113-
copier,
114-
this.messagingTrace,
115-
this.loggerFactory.CreateLogger<ClientGrainContext>());
115+
ServiceProvider.GetRequiredService<DeepCopier>(),
116+
messagingTrace,
117+
ServiceProvider.GetRequiredService<DeepCopier<Response>>(),
118+
_interfaceToImplementationMapping,
119+
loggerFactory.CreateLogger<ClientGrainContext>());
116120

117121
this.callbackTimerTask = Task.Run(MonitorCallbackExpiry);
118122

src/Orleans.Runtime/Core/HostedClient.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Orleans.Internal;
1313
using Orleans.Runtime.Messaging;
1414
using Orleans.Serialization;
15+
using Orleans.Serialization.Invocation;
1516

1617
namespace Orleans.Runtime
1718
{
@@ -24,7 +25,7 @@ internal sealed class HostedClient : IGrainContext, IGrainExtensionBinder, IDisp
2425
private readonly Channel<Message> incomingMessages;
2526
private readonly IGrainReferenceRuntime grainReferenceRuntime;
2627
private readonly InvokableObjectManager invokableObjects;
27-
private readonly IRuntimeClient runtimeClient;
28+
private readonly InsideRuntimeClient runtimeClient;
2829
private readonly ILogger logger;
2930
private readonly IInternalGrainFactory grainFactory;
3031
private readonly MessageCenter siloMessageCenter;
@@ -36,15 +37,16 @@ internal sealed class HostedClient : IGrainContext, IGrainExtensionBinder, IDisp
3637
private Task? messagePump;
3738

3839
public HostedClient(
39-
IRuntimeClient runtimeClient,
40+
InsideRuntimeClient runtimeClient,
4041
ILocalSiloDetails siloDetails,
4142
ILogger<HostedClient> logger,
4243
IGrainReferenceRuntime grainReferenceRuntime,
4344
IInternalGrainFactory grainFactory,
4445
MessageCenter messageCenter,
4546
MessagingTrace messagingTrace,
4647
DeepCopier deepCopier,
47-
GrainReferenceActivator referenceActivator)
48+
GrainReferenceActivator referenceActivator,
49+
InterfaceToImplementationMappingCache interfaceToImplementationMappingCache)
4850
{
4951
this.incomingMessages = Channel.CreateUnbounded<Message>(new UnboundedChannelOptions
5052
{
@@ -61,6 +63,8 @@ public HostedClient(
6163
runtimeClient,
6264
deepCopier,
6365
messagingTrace,
66+
runtimeClient.ServiceProvider.GetRequiredService<DeepCopier<Response>>(),
67+
interfaceToImplementationMappingCache,
6468
logger);
6569
this.siloMessageCenter = messageCenter;
6670
this.messagingTrace = messagingTrace;

src/Orleans.Runtime/Core/InsideRuntimeClient.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ internal sealed class InsideRuntimeClient : IRuntimeClient, ILifecycleParticipan
3131
private readonly ILoggerFactory loggerFactory;
3232
private readonly SiloMessagingOptions messagingOptions;
3333
private readonly ConcurrentDictionary<(GrainId, CorrelationId), CallbackData> callbacks;
34+
private readonly InterfaceToImplementationMappingCache interfaceToImplementationMapping;
3435
private readonly SharedCallbackData sharedCallbackData;
3536
private readonly SharedCallbackData systemSharedCallbackData;
3637
private readonly PeriodicTimer callbackTimer;
@@ -39,10 +40,9 @@ internal sealed class InsideRuntimeClient : IRuntimeClient, ILifecycleParticipan
3940
private MessageCenter messageCenter;
4041
private List<IIncomingGrainCallFilter> grainCallFilters;
4142
private readonly DeepCopier _deepCopier;
42-
private readonly InterfaceToImplementationMappingCache interfaceToImplementationMapping;
4343
private HostedClient hostedClient;
4444

45-
private HostedClient HostedClient => this.hostedClient ?? (this.hostedClient = this.ServiceProvider.GetRequiredService<HostedClient>());
45+
private HostedClient HostedClient => this.hostedClient ??= this.ServiceProvider.GetRequiredService<HostedClient>();
4646
private readonly MessageFactory messageFactory;
4747
private IGrainReferenceRuntime grainReferenceRuntime;
4848
private Task callbackTimerTask;
@@ -60,10 +60,11 @@ public InsideRuntimeClient(
6060
GrainInterfaceTypeResolver interfaceIdResolver,
6161
GrainInterfaceTypeToGrainTypeResolver interfaceToTypeResolver,
6262
DeepCopier deepCopier,
63-
TimeProvider timeProvider)
63+
TimeProvider timeProvider,
64+
InterfaceToImplementationMappingCache interfaceToImplementationMapping)
6465
{
6566
TimeProvider = timeProvider;
66-
this.interfaceToImplementationMapping = new InterfaceToImplementationMappingCache();
67+
this.interfaceToImplementationMapping = interfaceToImplementationMapping;
6768
this._deepCopier = deepCopier;
6869
this.ServiceProvider = serviceProvider;
6970
this.MySilo = siloDetails.SiloAddress;
@@ -102,7 +103,7 @@ private GrainLocator GrainLocator
102103
=> this.grainLocator ?? (this.grainLocator = this.ServiceProvider.GetRequiredService<GrainLocator>());
103104

104105
private List<IIncomingGrainCallFilter> GrainCallFilters
105-
=> this.grainCallFilters ?? (this.grainCallFilters = new List<IIncomingGrainCallFilter>(this.ServiceProvider.GetServices<IIncomingGrainCallFilter>()));
106+
=> this.grainCallFilters ??= new List<IIncomingGrainCallFilter>(this.ServiceProvider.GetServices<IIncomingGrainCallFilter>());
106107

107108
private MessageCenter MessageCenter => this.messageCenter ?? (this.messageCenter = this.ServiceProvider.GetRequiredService<MessageCenter>());
108109

src/Orleans.Runtime/Hosting/DefaultSiloServices.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ internal static void AddDefaultServices(ISiloBuilder builder)
100100
services.AddTransient<CancellationSourcesExtension>();
101101
services.AddKeyedTransient<IGrainExtension>(typeof(ICancellationSourcesExtension), (sp, _) => sp.GetRequiredService<CancellationSourcesExtension>());
102102
services.TryAddSingleton<GrainFactory>(sp => sp.GetRequiredService<InsideRuntimeClient>().ConcreteGrainFactory);
103+
services.TryAddSingleton<InterfaceToImplementationMappingCache>();
103104
services.TryAddSingleton<GrainInterfaceTypeToGrainTypeResolver>();
104105
services.TryAddFromExisting<IGrainFactory, GrainFactory>();
105106
services.TryAddFromExisting<IInternalGrainFactory, GrainFactory>();

0 commit comments

Comments
 (0)