-
Notifications
You must be signed in to change notification settings - Fork 26
Description
Problem Statement
Service registration is closed for extension and makes injecting additional dependencies within the SF service lifetime scope impossible. There is a challenge with proper initializing the Application Insights with Autofac. Based on AI for SF docu (https://github.com/microsoft/ApplicationInsights-ServiceFabric) there is a requirement to register FabricTelemetryInitializerExtension.CreateFabricTelemetryInitializer(ServiceContext) as a ITelemetryInitializer. However, this must be done while creating the lifetimescope in RegisterServiceAsync method. Otherwise, we don't have ServiceContext available.
Desired Solution
This can be easily achieved by adding additional parameter of type Action to RegisterStatefulServiceFactory/RegisterStatelessServiceFactory/RegisterActorFactory methods and make sure the parameter is passed from AutofacServiceExtensions class methods. Then in factory methods we can add custom dependencies in Begin scope action
var lifetimeScope = container.BeginLifetimeScope(tag, builder =>
{
builder.RegisterInstance(context)
.As<StatefulServiceContext>()
.As<ServiceContext>();
customRegistrations?.Invoke(builder);
});Then we could register service with following code:
Action<ContainerBuilder> configure = b =>
{
AppInsightsSupportInjectAction(b);
b.RegisterInstance(new StateManagerHolder());
b.Register(ctx => ctx.Resolve<StateManagerHolder>().StateManager ?? new ReliableStateManager(resolve(ctx)))
.As<IReliableStateManager>().InstancePerDependency();
};
try
{
containerBuilder.RegisterStatefulService<TService>(serviceTypeName, serviceTypeName, configure => configure.Register(ctx => FabricTelemetryInitializerExtension.CreateFabricTelemetryInitializer(ctx.Resolve<ServiceContext>()))Alternatives You've Considered
I haven't found any workaround to initialize the SF telemetry initializer in the scope created for SF service. I cannot do it in the Kestrel Webhost, as I have remoting methods (my service implements the SF's IService interface).
Additional Context
In my solution, I use a mix of HostBulder with Autofac along with Autofac SF integration so
registering FabricTelemetryInitializer out of service scope ends with exception as serviceContext is not resolved during the Build operation on HostBuilder. The reason for that is the AI integration which needs to resolve ILogger thus it pulls for all ITelemetryInitializers as well.
Additional benefit is that we could also register the IReliableStateManager. Now it's not possible because state manager is properly created withing the StatefulService and lifetime scope registration is being done befor. However with some helper class:
public class StateManagerHolder
{
/// <summary>
/// Gets or sets the state manager.
/// </summary>
public IReliableStateManager StateManager { get; set; }
}
we can inject additional registration
Action<ContainerBuilder> configure = b =>
{
b.RegisterInstance(new StateManagerHolder());
b.Register(ctx => ctx.Resolve<StateManagerHolder>().StateManager ?? new ReliableStateManager(resolve(ctx)))
.As<IReliableStateManager>().InstancePerDependency();
};
and make sure we update reference StateManager in RunAsync as follows:
var holder = this.rootScope.Resolve<StateManagerHolder>();
if (holder.StateManager == null)
{
holder.StateManager = this.StateManager;
}
the last step is required as for some reason new ReliableStateManager(resolve(ctx)) doesn't create valid reliable manager object - at least in my case injected stateful context in ctor is not assigned properly.