-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: Startup activation of singletons #86075
Comments
Tagging subscribers to this area: @dotnet/area-extensions-dependencyinjection Issue DetailsBackground and motivationCurrently, singleton dependencies are resolved at runtime when they are first requested. This could be an issue for response times and one might want them to be ready when the application starts. Another scenario is when the creation of a singleton should not block multiple requests that could be executed in parallel and be blocked (thundering herd). The proposal is to create new extension methods that will allow to register auto-activated dependencies. Internally it would use a specifically crafted API Proposalnamespace Microsoft.Extensions.DependencyInjection;
public static class AutoActivationExtensions
{
public static IServiceCollection Activate<TService>(this IServiceCollection services)
where TService : class
public static IServiceCollection AddActivatedSingleton<TService, TImplementation>(this IServiceCollection services, Func<IServiceProvider, TImplementation> implementationFactory)
where TService : class
where TImplementation : class, TService
public static IServiceCollection AddActivatedSingleton<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory)
where TService : class
public static IServiceCollection AddActivatedSingleton<TService>(this IServiceCollection services)
where TService : class
public static IServiceCollection AddActivatedSingleton(this IServiceCollection services, Type serviceType)
public static IServiceCollection AddActivatedSingleton<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
public static IServiceCollection AddActivatedSingleton(this IServiceCollection services, Type serviceType, Func<IServiceProvider, object> implementationFactory)
public static IServiceCollection AddActivatedSingleton(this IServiceCollection services, Type serviceType, Type implementationType)
public static void TryAddActivatedSingleton(this IServiceCollection services, Type serviceType)
public static void TryAddActivatedSingleton(this IServiceCollection services, Type serviceType, Type implementationType)
public static void TryAddActivatedSingleton(this IServiceCollection services, Type serviceType, Func<IServiceProvider, object> implementationFactory)
public static void TryAddActivatedSingleton<TService>(this IServiceCollection services)
where TService : class
public static void TryAddActivatedSingleton<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
public static void TryAddActivatedSingleton<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory)
where TService : class
} API Usage// Registers and auto-activates a class
builder.Services.AddActivatedSingleton<WindowsCounters>();
// Auto-activates a pre-registered singleton. If the service is not registered, System.InvalidOperationException is thrown.
builder.Services.AddSingleton<IFakeService, FakeService>().Activate<IFakeService>()); Alternative DesignsUser can already get this behavior by using available components: RisksNo response
|
I guess I see it as a callback like thing when service provider is constructed? If I'm right then maybe this can be generalized? I mean I saw an implementation idea using a Hosted service but maybe there is a need for a generalized version of this? Some kind of event. |
@cakescience I can see how this would also improve the first request latency, but it might also be counterproductive if you have services that are actually too expensive to initialize and are meant to be used in rare cases (or never...). So, opting-in might be less invasive. Also, singletons are the ones that are the most prone to taking a lot of time to initialize (pre-fetching configuration/long lived data). |
It seems like the implementation strategy would probably change pretty dramatically to support Scoped lifetimes (unless there is an equivalent to IHostedService that starts/stops whenever a new scope is created/destroyed) and it seems fundamentally incompatible with Transient lifetimes. It seems this functionality is already present in the preview, is that right? I noticed this was being used by |
@buyaa-n @steveharter any thoughts on this one? This is one of the components we have in dotnet/extensions repo but feel should move down to the platform. It would be really good to get this done by .NET 8 if possible but seems like our window is almost closing for this. |
This overlaps with #43149 and I'll work on closing that [update: done]. |
I'm proposing that we close this issue since there are several workarounds and a new extension: https://github.com/dotnet/extensions/blob/main/src/Libraries/Microsoft.Extensions.DependencyInjection.AutoActivation |
Makes sense to me. |
The AutoActivation extension essentially adds the APIs proposed in this issue. However, it doesn't address all scenarios, so I'll suggest moving to Future and not closing. I believe these APIs are common enough to add to the runtime repo, instead of an extension, but since there are several work-arounds including using the new extension, the priority for v8 at this point in the release is not that high. Some of the issues not addressed by the extension:
Also, the implementation:
|
@geeknoid If we already have the intention of moving the functionality down to the platform in the future, would it make sense to make the one in the extensions package "Experimental" in favor of a future move, or would it make more sense to keep as is and just mark as obsolete when we get to this work? |
We can't mark it experimental, since it would prevent us from depending on it from any other package, which makes it mostly useless. What would be the motivation to move this to dotnet/runtime in the future? Would there be a performance benefit, usability benefit, etc? |
It would be one less package to reference, and easily discovered through intellisense. We could push for this to get added to dotnet/runtime in v8. |
Closing; the implementation in the extensions repro is there and essentially what would be added to the runtime, and which could be added to the runtime in the future by re-implementing it with a different extension class or by using Type forwards if the behavior is the same. Without the extension, it is easy to work around by using |
I believe there were some use cases in dotnet/aspnetcore repo that could benefit from moving this down to dotnet/runtime (as aspnetcore can't depend on extensions due to circular dependencies), so if that's the case could we re-open this and just set the milestone to post-.NET 8? |
Background and motivation
Currently, singleton dependencies are resolved at runtime when they are first requested. This could be an issue for response times and one might want them to be ready when the application starts. Another scenario is when the creation of a singleton should not block multiple requests that could be executed in parallel and be blocked (thundering herd).
The proposal is to create new extension methods that will allow to register auto-activated dependencies. Internally it would use a specifically crafted
IHostedService
that would resolve them preemptively.API Proposal
API Usage
Alternative Designs
User can already get this behavior by using available components:
IHostedService
.Risks
No response
The text was updated successfully, but these errors were encountered: