Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 95a49ab

Browse files
committedMar 21, 2025·
Add additional context and logging when a grain class throws from its constructor.
1 parent aae6d57 commit 95a49ab

File tree

4 files changed

+36
-8
lines changed

4 files changed

+36
-8
lines changed
 

‎src/Orleans.Runtime/Activation/ActivationDataActivatorProvider.cs

+7
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,14 @@ private class ActivationDataActivator : IGrainContextActivator
8585
private readonly IGrainActivator _grainActivator;
8686
private readonly IServiceProvider _serviceProvider;
8787
private readonly GrainTypeSharedContext _sharedComponents;
88+
private readonly ILogger<Grain> _grainLogger;
8889
private readonly Func<IGrainContext, WorkItemGroup> _createWorkItemGroup;
8990

9091
public ActivationDataActivator(
9192
IGrainActivator grainActivator,
9293
IServiceProvider serviceProvider,
9394
GrainTypeSharedContext sharedComponents,
95+
ILogger<Grain> grainLogger,
9496
ILogger<WorkItemGroup> workItemGroupLogger,
9597
ILogger<ActivationTaskScheduler> activationTaskSchedulerLogger,
9698
IOptions<SchedulingOptions> schedulingOptions)
@@ -101,6 +103,7 @@ public ActivationDataActivator(
101103
_grainActivator = grainActivator;
102104
_serviceProvider = serviceProvider;
103105
_sharedComponents = sharedComponents;
106+
_grainLogger = grainLogger;
104107
_createWorkItemGroup = context => new WorkItemGroup(
105108
context,
106109
_workItemGroupLogger,
@@ -124,6 +127,10 @@ public IGrainContext CreateContext(GrainAddress activationAddress)
124127
var instance = _grainActivator.CreateInstance(context);
125128
context.SetGrainInstance(instance);
126129
}
130+
catch (Exception exception)
131+
{
132+
_grainLogger.LogError(exception, "Failed to construct grain '{GrainId}'.", activationAddress.GrainId);
133+
}
127134
finally
128135
{
129136
RuntimeContext.ResetExecutionContext(originalContext);

‎src/Orleans.Runtime/Activation/DefaultGrainActivator.cs

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Threading.Tasks;
33
using Microsoft.Extensions.DependencyInjection;
44

@@ -11,6 +11,7 @@ public class DefaultGrainActivator : IGrainActivator
1111
{
1212
private readonly ObjectFactory _grainInstanceFactory;
1313
private readonly GrainConstructorArgumentFactory _argumentFactory;
14+
private readonly Type _grainClass;
1415

1516
/// <summary>
1617
/// Initializes a new <see cref="DefaultGrainActivator"/> instance.
@@ -21,13 +22,23 @@ public DefaultGrainActivator(IServiceProvider serviceProvider, Type grainClass)
2122
{
2223
_argumentFactory = new GrainConstructorArgumentFactory(serviceProvider, grainClass);
2324
_grainInstanceFactory = ActivatorUtilities.CreateFactory(grainClass, _argumentFactory.ArgumentTypes);
25+
_grainClass = grainClass;
2426
}
2527

2628
/// <inheritdoc/>
2729
public object CreateInstance(IGrainContext context)
2830
{
29-
var args = _argumentFactory.CreateArguments(context);
30-
return _grainInstanceFactory(context.ActivationServices, args);
31+
try
32+
{
33+
var args = _argumentFactory.CreateArguments(context);
34+
return _grainInstanceFactory(context.ActivationServices, args);
35+
}
36+
catch (Exception exception)
37+
{
38+
throw new InvalidOperationException(
39+
$"Failed to create an instance of grain type '{_grainClass}'. See {nameof(Exception.InnerException)} for details.",
40+
exception);
41+
}
3142
}
3243

3344
/// <inheritdoc/>

‎src/Orleans.Runtime/Facet/GrainConstructorArgumentFactory.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public GrainConstructorArgumentFactory(IServiceProvider serviceProvider, Type gr
3737

3838
// Since the IAttributeToFactoryMapper is specific to the attribute specialization, we create a generic method to provide a attribute independent call pattern.
3939
var getFactory = GetFactoryMethod.MakeGenericMethod(attribute.GetType());
40-
var argumentFactory = (Factory<IGrainContext, object>)getFactory.Invoke(this, new object[] { serviceProvider, parameter, attribute, grainType });
40+
var argumentFactory = (Factory<IGrainContext, object>)getFactory.Invoke(this, [serviceProvider, parameter, attribute, grainType]);
4141

4242
// Record the argument factory
4343
_argumentFactories.Add(argumentFactory);

‎src/Orleans.Runtime/Facet/Persistent/PersistentStateAttributeMapper.cs

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Reflection;
23
using Microsoft.Extensions.DependencyInjection;
34
using Orleans.Runtime;
@@ -9,7 +10,7 @@ namespace Orleans
910
/// </summary>
1011
public class PersistentStateAttributeMapper : IAttributeToFactoryMapper<PersistentStateAttribute>
1112
{
12-
private static readonly MethodInfo create = typeof(IPersistentStateFactory).GetMethod("Create");
13+
private static readonly MethodInfo CreateMethodInfo = typeof(IPersistentStateFactory).GetMethod("Create");
1314

1415
/// <inheritdoc/>
1516
public Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, PersistentStateAttribute attribute)
@@ -20,15 +21,24 @@ public Factory<IGrainContext, object> GetFactory(ParameterInfo parameter, Persis
2021
{
2122
config = new PersistentStateConfiguration() { StateName = parameter.Name, StorageName = attribute.StorageName };
2223
}
24+
25+
if (!parameter.ParameterType.IsGenericType || !typeof(IPersistentState<>).Equals(parameter.ParameterType.GetGenericTypeDefinition()))
26+
{
27+
throw new ArgumentException(
28+
$"Parameter '{parameter.Name}' on the constructor for '{parameter.Member.DeclaringType}' has an unsupported type, '{parameter.ParameterType}'. "
29+
+ $"It must be an instance of generic type '{typeof(IPersistentState<>)}' because it has an associated [PersistentState(...)] attribute.",
30+
parameter.Name);
31+
}
32+
2333
// use generic type args to define collection type.
24-
MethodInfo genericCreate = create.MakeGenericMethod(parameter.ParameterType.GetGenericArguments());
34+
MethodInfo genericCreate = CreateMethodInfo.MakeGenericMethod(parameter.ParameterType.GetGenericArguments());
2535
return context => Create(context, genericCreate, config);
2636
}
2737

28-
private object Create(IGrainContext context, MethodInfo genericCreate, IPersistentStateConfiguration config)
38+
private static object Create(IGrainContext context, MethodInfo genericCreate, IPersistentStateConfiguration config)
2939
{
3040
IPersistentStateFactory factory = context.ActivationServices.GetRequiredService<IPersistentStateFactory>();
31-
object[] args = new object[] { context, config };
41+
object[] args = [context, config];
3242
return genericCreate.Invoke(factory, args);
3343
}
3444

0 commit comments

Comments
 (0)
Please sign in to comment.