/
vshmidt
/
Hangfire
Обзор
Документация
Войти
/
vshmidt
/
Hangfire
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Hangfire.NetCore/HangfireServiceCollectionExtensions.cs
315 строк
14 KB
Sergey Odinokov
Use C# 7.3's static anonymous functions to have less allocations
06 июн 2024, 14:42
06 июн 2024, 14:42
f052283
Код
Авторство
О чём код?
// This file is part of Hangfire. Copyright © 2016 Hangfire OÜ. // // Hangfire is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation, either version 3 // of the License, or any later version. // // Hangfire is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with Hangfire. If not, see <http://www.gnu.org/licenses/>. using System; using System.Collections.Generic; using Hangfire.Annotations; using Hangfire.AspNetCore; using Hangfire.Client; using Hangfire.Common; using Hangfire.Dashboard; using Hangfire.Server; using Hangfire.States; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; #if !NET451 && !NETSTANDARD1_3 using Microsoft.Extensions.Hosting; #endif namespace Hangfire { public static class HangfireServiceCollectionExtensions { public static IServiceCollection AddHangfire( [NotNull] this IServiceCollection services, [NotNull] Action<IGlobalConfiguration> configuration) { return AddHangfire(services, (provider, config) => configuration(config)); } public static IServiceCollection AddHangfire( [NotNull] this IServiceCollection services, [NotNull] Action<IServiceProvider, IGlobalConfiguration> configuration) { if (services == null) throw new ArgumentNullException(nameof(services)); if (configuration == null) throw new ArgumentNullException(nameof(configuration)); services.TryAddSingletonChecked(static _ => JobStorage.Current); services.TryAddSingletonChecked(static _ => JobActivator.Current); services.TryAddSingleton(static _ => DashboardRoutes.Routes); services.TryAddSingleton<IJobFilterProvider>(static _ => JobFilterProviders.Providers); services.TryAddSingleton<ITimeZoneResolver>(static _ => new DefaultTimeZoneResolver()); services.TryAddSingleton(static x => new DefaultClientManagerFactory(x)); services.TryAddSingletonChecked<IBackgroundJobClientFactory>(static x => x.GetService<DefaultClientManagerFactory>()); services.TryAddSingletonChecked<IBackgroundJobClientFactoryV2>(static x => x.GetService<DefaultClientManagerFactory>()); services.TryAddSingletonChecked<IRecurringJobManagerFactory>(static x => x.GetService<DefaultClientManagerFactory>()); services.TryAddSingletonChecked<IRecurringJobManagerFactoryV2>(static x => x.GetService<DefaultClientManagerFactory>()); services.TryAddSingletonChecked(static x => x .GetService<IBackgroundJobClientFactory>().GetClient(x.GetService<JobStorage>())); services.TryAddSingletonChecked(static x => x .GetService<IBackgroundJobClientFactoryV2>().GetClientV2(x.GetService<JobStorage>())); services.TryAddSingletonChecked(static x => x .GetService<IRecurringJobManagerFactory>().GetManager(x.GetService<JobStorage>())); services.TryAddSingletonChecked(static x => x .GetService<IRecurringJobManagerFactoryV2>().GetManagerV2(x.GetService<JobStorage>())); // IGlobalConfiguration serves as a marker indicating that Hangfire's services // were added to the service container (checked by IApplicationBuilder extensions). // // Being a singleton, it also guarantees that the configuration callback will be // executed just once upon initialization, so there's no need to double-check that. // // It should never be replaced by another implementation !!! // AddSingleton() will throw an exception if it was already registered services.AddSingleton<IGlobalConfiguration>(serviceProvider => { var configurationInstance = GlobalConfiguration.Configuration; // init defaults for log provider and job activator // they may be overwritten by the configuration callback later var loggerFactory = serviceProvider.GetService<ILoggerFactory>(); if (loggerFactory != null) { configurationInstance.UseLogProvider(new AspNetCoreLogProvider(loggerFactory)); } var scopeFactory = serviceProvider.GetService<IServiceScopeFactory>(); if (scopeFactory != null) { configurationInstance.UseActivator(new AspNetCoreJobActivator(scopeFactory)); } // do configuration inside callback configuration(serviceProvider, configurationInstance); return configurationInstance; }); return services; } #if !NET451 && !NETSTANDARD1_3 public static IServiceCollection AddHangfireServer( [NotNull] this IServiceCollection services, [NotNull] Action<BackgroundJobServerOptions> optionsAction) { if (services == null) throw new ArgumentNullException(nameof(services)); if (optionsAction == null) throw new ArgumentNullException(nameof(optionsAction)); return AddHangfireServerInner(services, null, null, (provider, options) => optionsAction(options)); } public static IServiceCollection AddHangfireServer( [NotNull] this IServiceCollection services, [NotNull] Action<IServiceProvider, BackgroundJobServerOptions> optionsAction) { if (services == null) throw new ArgumentNullException(nameof(services)); if (optionsAction == null) throw new ArgumentNullException(nameof(optionsAction)); return AddHangfireServerInner(services, null, null, optionsAction); } public static IServiceCollection AddHangfireServer( [NotNull] this IServiceCollection services, [NotNull] Action<IServiceProvider, BackgroundJobServerOptions> optionsAction, [NotNull] JobStorage storage) { if (services == null) throw new ArgumentNullException(nameof(services)); if (optionsAction == null) throw new ArgumentNullException(nameof(optionsAction)); if (storage == null) throw new ArgumentNullException(nameof(storage)); return AddHangfireServerInner(services, storage, null, optionsAction); } public static IServiceCollection AddHangfireServer( [NotNull] this IServiceCollection services, [NotNull] Action<IServiceProvider, BackgroundJobServerOptions> optionsAction, [NotNull] JobStorage storage, [NotNull] IEnumerable<IBackgroundProcess> additionalProcesses) { if (services == null) throw new ArgumentNullException(nameof(services)); if (optionsAction == null) throw new ArgumentNullException(nameof(optionsAction)); if (storage == null) throw new ArgumentNullException(nameof(storage)); if (additionalProcesses == null) throw new ArgumentNullException(nameof(additionalProcesses)); return AddHangfireServerInner(services, storage, additionalProcesses, optionsAction); } public static IServiceCollection AddHangfireServer([NotNull] this IServiceCollection services) { if (services == null) throw new ArgumentNullException(nameof(services)); return AddHangfireServerInner(services, null, null); } public static IServiceCollection AddHangfireServer( [NotNull] this IServiceCollection services, [NotNull] JobStorage storage) { if (services == null) throw new ArgumentNullException(nameof(services)); if (storage == null) throw new ArgumentNullException(nameof(storage)); return AddHangfireServerInner(services, storage, null); } public static IServiceCollection AddHangfireServer( [NotNull] this IServiceCollection services, [NotNull] JobStorage storage, [NotNull] IEnumerable<IBackgroundProcess> additionalProcesses) { if (services == null) throw new ArgumentNullException(nameof(services)); if (storage == null) throw new ArgumentNullException(nameof(storage)); if (additionalProcesses == null) throw new ArgumentNullException(nameof(additionalProcesses)); return AddHangfireServerInner(services, storage, additionalProcesses); } private static IServiceCollection AddHangfireServerInner( [NotNull] IServiceCollection services, [CanBeNull] JobStorage storage, [CanBeNull] IEnumerable<IBackgroundProcess> additionalProcesses) { services.AddTransient<IHostedService, BackgroundJobServerHostedService>(provider => { var options = provider.GetService<BackgroundJobServerOptions>() ?? new BackgroundJobServerOptions(); return CreateBackgroundJobServerHostedService(provider, storage, additionalProcesses, options); }); return services; } private static IServiceCollection AddHangfireServerInner( [NotNull] IServiceCollection services, [CanBeNull] JobStorage storage, [CanBeNull] IEnumerable<IBackgroundProcess> additionalProcesses, [NotNull] Action<IServiceProvider, BackgroundJobServerOptions> optionsAction) { services.AddTransient<IHostedService, BackgroundJobServerHostedService>(provider => { var options = new BackgroundJobServerOptions(); optionsAction(provider, options); return CreateBackgroundJobServerHostedService(provider, storage, additionalProcesses, options); }); return services; } public static IServiceCollection AddHangfireServer( [NotNull] this IServiceCollection services, [NotNull] Func<IServiceProvider, IBackgroundProcessingServer> implementationFactory) { if (services == null) throw new ArgumentNullException(nameof(services)); if (implementationFactory == null) throw new ArgumentNullException(nameof(implementationFactory)); services.AddTransient<IHostedService, BackgroundProcessingServerHostedService>( provider => new BackgroundProcessingServerHostedService( implementationFactory(provider) #if NETSTANDARD2_1 , provider.GetService<IHostApplicationLifetime>() #endif )); return services; } private static BackgroundJobServerHostedService CreateBackgroundJobServerHostedService( IServiceProvider provider, JobStorage storage, IEnumerable<IBackgroundProcess> additionalProcesses, BackgroundJobServerOptions options) { ThrowIfNotConfigured(provider); storage = storage ?? provider.GetService<JobStorage>() ?? JobStorage.Current; additionalProcesses = additionalProcesses ?? provider.GetServices<IBackgroundProcess>(); options.Activator = options.Activator ?? provider.GetService<JobActivator>(); options.FilterProvider = options.FilterProvider ?? provider.GetService<IJobFilterProvider>(); options.TimeZoneResolver = options.TimeZoneResolver ?? provider.GetService<ITimeZoneResolver>(); GetInternalServices(provider, out var factory, out var stateChanger, out var performer); #if NETSTANDARD2_1 || NETCOREAPP3_0_OR_GREATER var lifetime = provider.GetService<IHostApplicationLifetime>(); #endif #pragma warning disable 618 return new BackgroundJobServerHostedService( #pragma warning restore 618 storage, options, additionalProcesses, factory, performer, stateChanger #if NETSTANDARD2_1 || NETCOREAPP3_0_OR_GREATER , lifetime #endif ); } #endif public static bool GetInternalServices( IServiceProvider provider, out IBackgroundJobFactory factory, out IBackgroundJobStateChanger stateChanger, out IBackgroundJobPerformer performer) { factory = provider.GetService<IBackgroundJobFactory>(); performer = provider.GetService<IBackgroundJobPerformer>(); stateChanger = provider.GetService<IBackgroundJobStateChanger>(); if (factory != null && performer != null && stateChanger != null) { return true; } factory = null; performer = null; stateChanger = null; return false; } private static void TryAddSingletonChecked<T>( [NotNull] this IServiceCollection serviceCollection, [NotNull] Func<IServiceProvider, T> implementationFactory) where T : class { serviceCollection.TryAddSingleton<T>(serviceProvider => { if (serviceProvider == null) throw new ArgumentNullException(nameof(serviceProvider)); // ensure the configuration was performed serviceProvider.GetRequiredService<IGlobalConfiguration>(); return implementationFactory(serviceProvider); }); } public static void ThrowIfNotConfigured(IServiceProvider serviceProvider) { var configuration = serviceProvider.GetService<IGlobalConfiguration>(); if (configuration == null) { throw new InvalidOperationException( "Unable to find the required services. Please add all the required services by calling 'IServiceCollection.AddHangfire' inside the call to 'ConfigureServices(...)' in the application startup code."); } } } }