diff --git a/src/core/Elsa.Jobs/Contracts/ISchedulingServiceProvider.cs b/src/core/Elsa.Jobs/Contracts/IJobQueueProvider.cs similarity index 76% rename from src/core/Elsa.Jobs/Contracts/ISchedulingServiceProvider.cs rename to src/core/Elsa.Jobs/Contracts/IJobQueueProvider.cs index 674d1aa07..eed0cf637 100644 --- a/src/core/Elsa.Jobs/Contracts/ISchedulingServiceProvider.cs +++ b/src/core/Elsa.Jobs/Contracts/IJobQueueProvider.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; namespace Elsa.Jobs.Contracts; -public interface ISchedulingServiceProvider +public interface IJobQueueProvider { void ConfigureServices(IServiceCollection services); } \ No newline at end of file diff --git a/src/core/Elsa.Jobs/Contracts/IJobSchedulerProvider.cs b/src/core/Elsa.Jobs/Contracts/IJobSchedulerProvider.cs new file mode 100644 index 000000000..fbd0f6370 --- /dev/null +++ b/src/core/Elsa.Jobs/Contracts/IJobSchedulerProvider.cs @@ -0,0 +1,8 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.Jobs.Contracts; + +public interface IJobSchedulerProvider +{ + void ConfigureServices(IServiceCollection services); +} \ No newline at end of file diff --git a/src/core/Elsa.Jobs/Contracts/IJobSerializer.cs b/src/core/Elsa.Jobs/Contracts/IJobSerializer.cs new file mode 100644 index 000000000..c2124fc0d --- /dev/null +++ b/src/core/Elsa.Jobs/Contracts/IJobSerializer.cs @@ -0,0 +1,7 @@ +namespace Elsa.Jobs.Contracts; + +public interface IJobSerializer +{ + string Serialize(IJob job); + T Deserialize(string json) where T : IJob; +} \ No newline at end of file diff --git a/src/core/Elsa.Jobs/Extensions/ServiceCollectionExtensions.cs b/src/core/Elsa.Jobs/Extensions/ServiceCollectionExtensions.cs index 3f35f3b0a..3c6c7ff28 100644 --- a/src/core/Elsa.Jobs/Extensions/ServiceCollectionExtensions.cs +++ b/src/core/Elsa.Jobs/Extensions/ServiceCollectionExtensions.cs @@ -6,11 +6,14 @@ namespace Elsa.Jobs.Extensions; public static class ServiceCollectionExtensions { - public static IServiceCollection AddJobs(this IServiceCollection services, ISchedulingServiceProvider serviceProvider) + public static IServiceCollection AddJobs(this IServiceCollection services, IJobSchedulerProvider schedulerProvider, IJobQueueProvider queueProvider) { - services.AddSingleton(); + services + .AddSingleton() + .AddSingleton(); - serviceProvider.ConfigureServices(services); + schedulerProvider.ConfigureServices(services); + queueProvider.ConfigureServices(services); return services; } diff --git a/src/modules/Elsa.Modules.Quartz/Services/ElsaJobSerializer.cs b/src/core/Elsa.Jobs/Services/JobSerializer.cs similarity index 80% rename from src/modules/Elsa.Modules.Quartz/Services/ElsaJobSerializer.cs rename to src/core/Elsa.Jobs/Services/JobSerializer.cs index 62c1166ed..bf3483b45 100644 --- a/src/modules/Elsa.Modules.Quartz/Services/ElsaJobSerializer.cs +++ b/src/core/Elsa.Jobs/Services/JobSerializer.cs @@ -1,10 +1,9 @@ using System.Text.Json; using Elsa.Jobs.Contracts; -using Elsa.Modules.Quartz.Contracts; -namespace Elsa.Modules.Quartz.Services; +namespace Elsa.Jobs.Services; -public class ElsaJobSerializer : IElsaJobSerializer +public class JobSerializer : IJobSerializer { public string Serialize(IJob job) { diff --git a/src/modules/Elsa.Modules.Hangfire/Elsa.Modules.Hangfire.csproj b/src/modules/Elsa.Modules.Hangfire/Elsa.Modules.Hangfire.csproj index 22f53132a..42028df37 100644 --- a/src/modules/Elsa.Modules.Hangfire/Elsa.Modules.Hangfire.csproj +++ b/src/modules/Elsa.Modules.Hangfire/Elsa.Modules.Hangfire.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/modules/Elsa.Modules.Hangfire/Extensions/ServiceCollectionExtensions.cs b/src/modules/Elsa.Modules.Hangfire/Extensions/ServiceCollectionExtensions.cs index fe1ecaf18..65a9e92a2 100644 --- a/src/modules/Elsa.Modules.Hangfire/Extensions/ServiceCollectionExtensions.cs +++ b/src/modules/Elsa.Modules.Hangfire/Extensions/ServiceCollectionExtensions.cs @@ -4,12 +4,4 @@ namespace Elsa.Modules.Hangfire.Extensions; public static class ServiceCollectionExtensions { - /// - /// Registers both Hangfire and Elsa specific services. - /// If you register Hangfire yourself, use - /// - public static IServiceCollection AddHangfireAndModule(this IServiceCollection services) - { - - } } \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueueProvider.cs b/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueueProvider.cs new file mode 100644 index 000000000..63318d677 --- /dev/null +++ b/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueueProvider.cs @@ -0,0 +1,41 @@ +using Elsa.Jobs.Contracts; +using Hangfire; +using Hangfire.SqlServer; +using Microsoft.Extensions.DependencyInjection; + +namespace Elsa.Modules.Hangfire.Services; + +public class HangfireJobQueueProvider : IJobQueueProvider +{ + public HangfireJobQueueProvider(bool registerHangfire = true) + { + RegisterHangfire = registerHangfire; + } + + public HangfireJobQueueProvider(string sqlServerConnectionString) + { + SqlServerConnectionString = sqlServerConnectionString; + UseSqlServerStorage = true; + RegisterHangfire = true; + } + + public bool RegisterHangfire { get; set; } + public bool UseSqlServerStorage { get; set; } + public string? SqlServerConnectionString { get; set; } + public SqlServerStorageOptions? SqlServerStorageOptions { get; set; } + + public void ConfigureServices(IServiceCollection services) + { + if (RegisterHangfire) + { + var storageOptions = SqlServerStorageOptions ?? new SqlServerStorageOptions(); + + services + .AddHangfire(configuration => configuration + .UseSimpleAssemblyNameTypeSerializer() + .UseSqlServerStorage(SqlServerConnectionString, storageOptions)); + } + + services.AddSingleton(); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Quartz/Contracts/IElsaJobSerializer.cs b/src/modules/Elsa.Modules.Quartz/Contracts/IElsaJobSerializer.cs deleted file mode 100644 index faa0ef425..000000000 --- a/src/modules/Elsa.Modules.Quartz/Contracts/IElsaJobSerializer.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Elsa.Jobs.Contracts; - -namespace Elsa.Modules.Quartz.Contracts; - -public interface IElsaJobSerializer -{ - string Serialize(IJob job); - T Deserialize(string json) where T : IJob; -} \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Quartz/Elsa.Modules.Quartz.csproj b/src/modules/Elsa.Modules.Quartz/Elsa.Modules.Quartz.csproj index 2e591c515..5dee58628 100644 --- a/src/modules/Elsa.Modules.Quartz/Elsa.Modules.Quartz.csproj +++ b/src/modules/Elsa.Modules.Quartz/Elsa.Modules.Quartz.csproj @@ -16,4 +16,8 @@ + + + + diff --git a/src/modules/Elsa.Modules.Quartz/Extensions/ServiceCollectionExtensions.cs b/src/modules/Elsa.Modules.Quartz/Extensions/ServiceCollectionExtensions.cs index ab410ed40..c49ab6c90 100644 --- a/src/modules/Elsa.Modules.Quartz/Extensions/ServiceCollectionExtensions.cs +++ b/src/modules/Elsa.Modules.Quartz/Extensions/ServiceCollectionExtensions.cs @@ -1,9 +1,5 @@ -using Elsa.Jobs.Contracts; -using Elsa.Modules.Quartz.Contracts; using Elsa.Modules.Quartz.Jobs; -using Elsa.Modules.Quartz.Services; using Elsa.Modules.Scheduling.Jobs; -using Microsoft.Extensions.DependencyInjection; using Quartz; using IJob = Elsa.Jobs.Contracts.IJob; @@ -11,43 +7,7 @@ namespace Elsa.Modules.Quartz.Extensions; public static class ServiceCollectionExtensions { - /// - /// Registers both Quartz as well as Elsa-specific services and jobs. - /// If you register Quartz yourself, use instead. - /// - public static IServiceCollection AddQuartzAndModule( - this IServiceCollection services, - Action? configureQuartzOptions = default, - Action? configureQuartz = default, - Action? configureQuartzHostedService = default) - { - if (configureQuartzOptions != null) - services.Configure(configureQuartzOptions); - - return services - .AddQuartz(configure => - { - ConfigureQuartz(configure, configureQuartz); - AddQuartzModule(services, configure); - }) - .AddQuartzHostedService(options => ConfigureQuartzHostedService(options, configureQuartzHostedService)); - } - - /// - /// This will register Elsa-specific services and jobs, but will **not** register Quartz itself. To register Quartz, you need to do so yourself, or use to register & configure Quartz for Elsa. - /// - public static IServiceCollection AddQuartzModule(this IServiceCollection services, IServiceCollectionQuartzConfigurator quartz) - { - services - .AddSingleton() - .AddSingleton(); - - quartz.AddElsaJobs(); - - return services; - } - - private static IServiceCollectionQuartzConfigurator AddElsaJobs(this IServiceCollectionQuartzConfigurator quartz) + public static IServiceCollectionQuartzConfigurator AddElsaJobs(this IServiceCollectionQuartzConfigurator quartz) { quartz.AddJob(); quartz.AddJob(); @@ -55,20 +15,6 @@ public static class ServiceCollectionExtensions return quartz; } - private static void ConfigureQuartzHostedService(QuartzHostedServiceOptions options, Action? configureQuartzHostedService) - { - options.WaitForJobsToComplete = true; - configureQuartzHostedService?.Invoke(options); - } - private static IServiceCollectionQuartzConfigurator AddJob(this IServiceCollectionQuartzConfigurator quartz) where TJob : IJob => quartz.AddJob>(job => job.StoreDurably().WithIdentity(typeof(TJob).Name)); - - private static void ConfigureQuartz(IServiceCollectionQuartzConfigurator quartz, Action? configureQuartz) - { - quartz.UseMicrosoftDependencyInjectionJobFactory(); - quartz.UseSimpleTypeLoader(); - quartz.UseInMemoryStore(); - configureQuartz?.Invoke(quartz); - } } \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Quartz/Jobs/QuartzJob.cs b/src/modules/Elsa.Modules.Quartz/Jobs/QuartzJob.cs index d7aeea5f3..42d7237c9 100644 --- a/src/modules/Elsa.Modules.Quartz/Jobs/QuartzJob.cs +++ b/src/modules/Elsa.Modules.Quartz/Jobs/QuartzJob.cs @@ -1,5 +1,4 @@ using Elsa.Jobs.Contracts; -using Elsa.Modules.Quartz.Contracts; using Elsa.Modules.Quartz.Services; using Quartz; using IJob = Elsa.Jobs.Contracts.IJob; @@ -13,19 +12,19 @@ namespace Elsa.Modules.Quartz.Jobs; /// public class QuartzJob : IQuartzJob where TElsaJob : IJob { - private readonly IElsaJobSerializer _elsaJobSerializer; + private readonly IJobSerializer _jobSerializer; private readonly IJobRunner _jobRunner; - public QuartzJob(IElsaJobSerializer elsaJobSerializer, IJobRunner jobRunner) + public QuartzJob(IJobSerializer jobSerializer, IJobRunner jobRunner) { - _elsaJobSerializer = elsaJobSerializer; + _jobSerializer = jobSerializer; _jobRunner = jobRunner; } public async Task Execute(IJobExecutionContext context) { var json = context.MergedJobDataMap.GetString(QuartzJobScheduler.JobDataKey)!; - var elsaJob = _elsaJobSerializer.Deserialize(json); + var elsaJob = _jobSerializer.Deserialize(json); await _jobRunner.RunJobAsync(elsaJob, context.CancellationToken); } } \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Quartz/Services/QuartzJobScheduler.cs b/src/modules/Elsa.Modules.Quartz/Services/QuartzJobScheduler.cs index f95cea79f..e37dc3165 100644 --- a/src/modules/Elsa.Modules.Quartz/Services/QuartzJobScheduler.cs +++ b/src/modules/Elsa.Modules.Quartz/Services/QuartzJobScheduler.cs @@ -1,6 +1,5 @@ using Elsa.Jobs.Contracts; using Elsa.Jobs.Schedules; -using Elsa.Modules.Quartz.Contracts; using Microsoft.Extensions.Logging; using Quartz; using Quartz.Impl.Matchers; @@ -14,13 +13,13 @@ public class QuartzJobScheduler : IJobScheduler { public const string JobDataKey = "ElsaJob"; public const string RootGroupKey = "ElsaJobs"; - private readonly IElsaJobSerializer _elsaJobSerializer; + private readonly IJobSerializer _jobSerializer; private readonly ISchedulerFactory _schedulerFactory; private readonly ILogger _logger; - public QuartzJobScheduler(IElsaJobSerializer elsaJobSerializer, ISchedulerFactory schedulerFactory, ILogger logger) + public QuartzJobScheduler(IJobSerializer jobSerializer, ISchedulerFactory schedulerFactory, ILogger logger) { - _elsaJobSerializer = elsaJobSerializer; + _jobSerializer = jobSerializer; _schedulerFactory = schedulerFactory; _logger = logger; } @@ -66,7 +65,7 @@ public class QuartzJobScheduler : IJobScheduler var jobName = job.GetType().Name; var groupKey = BuildGroupKey(groupKeys); var triggerKey = new TriggerKey(job.JobId, groupKey); - var json = _elsaJobSerializer.Serialize(job); + var json = _jobSerializer.Serialize(job); var builder = TriggerBuilder.Create().ForJob(jobName).WithIdentity(triggerKey).UsingJobData(JobDataKey, json); switch (schedule) diff --git a/src/modules/Elsa.Modules.Quartz/Services/QuartzJobSchedulerProvider.cs b/src/modules/Elsa.Modules.Quartz/Services/QuartzJobSchedulerProvider.cs new file mode 100644 index 000000000..4d5c0b0f4 --- /dev/null +++ b/src/modules/Elsa.Modules.Quartz/Services/QuartzJobSchedulerProvider.cs @@ -0,0 +1,80 @@ +using Elsa.Jobs.Contracts; +using Elsa.Modules.Quartz.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Quartz; + +namespace Elsa.Modules.Quartz.Services; + +/// +/// A Quartz.NET implementation for . +/// +public class QuartzJobSchedulerProvider : IJobSchedulerProvider +{ + public QuartzJobSchedulerProvider(bool registerQuartz = true) + { + RegisterQuartz = registerQuartz; + } + + public QuartzJobSchedulerProvider(Action configureQuartzOptions) + { + RegisterQuartz = true; + ConfigureQuartzOptions = configureQuartzOptions; + } + + public QuartzJobSchedulerProvider( + Action configureQuartzOptions, + Action configureQuartz) + { + RegisterQuartz = true; + ConfigureQuartzOptions = configureQuartzOptions; + ConfigureQuartz = configureQuartz; + } + + public QuartzJobSchedulerProvider( + Action configureQuartzOptions, + Action configureQuartz, + Action configureQuartzHostedService) + { + RegisterQuartz = true; + ConfigureQuartzOptions = configureQuartzOptions; + ConfigureQuartz = configureQuartz; + ConfigureQuartzHostedService = configureQuartzHostedService; + } + + public bool RegisterQuartz { get; set; } + public Action? ConfigureQuartzOptions { get; set; } + public Action? ConfigureQuartz { get; set; } + public Action? ConfigureQuartzHostedService { get; set; } + + public void ConfigureServices(IServiceCollection services) + { + if (RegisterQuartz) + { + if (ConfigureQuartzOptions != null) + services.Configure(ConfigureQuartzOptions); + + services + .AddQuartz(configure => + { + ConfigureQuartzInternal(configure, ConfigureQuartz); + configure.AddElsaJobs(); + }) + .AddQuartzHostedService(options => + { + options.WaitForJobsToComplete = true; + ConfigureQuartzHostedService?.Invoke(options); + }); + } + + services.AddSingleton(); + + } + + private static void ConfigureQuartzInternal(IServiceCollectionQuartzConfigurator quartz, Action? configureQuartz) + { + quartz.UseMicrosoftDependencyInjectionJobFactory(); + quartz.UseSimpleTypeLoader(); + quartz.UseInMemoryStore(); + configureQuartz?.Invoke(quartz); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Quartz/Services/QuartzSchedulingServiceProvider.cs b/src/modules/Elsa.Modules.Quartz/Services/QuartzSchedulingServiceProvider.cs deleted file mode 100644 index 035b58168..000000000 --- a/src/modules/Elsa.Modules.Quartz/Services/QuartzSchedulingServiceProvider.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Elsa.Jobs.Contracts; -using Elsa.Modules.Quartz.Extensions; -using Microsoft.Extensions.DependencyInjection; - -namespace Elsa.Modules.Quartz.Services; - -public class QuartzSchedulingServiceProvider : ISchedulingServiceProvider -{ - public void ConfigureServices(IServiceCollection services) - { - services.AddQuartzAndModule(); - } -} \ No newline at end of file diff --git a/src/samples/aspnet/Elsa.Samples.Web1/Elsa.Samples.Web1.csproj b/src/samples/aspnet/Elsa.Samples.Web1/Elsa.Samples.Web1.csproj index f7a700659..d3338bb94 100644 --- a/src/samples/aspnet/Elsa.Samples.Web1/Elsa.Samples.Web1.csproj +++ b/src/samples/aspnet/Elsa.Samples.Web1/Elsa.Samples.Web1.csproj @@ -7,6 +7,7 @@ + diff --git a/src/samples/aspnet/Elsa.Samples.Web1/Program.cs b/src/samples/aspnet/Elsa.Samples.Web1/Program.cs index 14475049b..39035cd65 100644 --- a/src/samples/aspnet/Elsa.Samples.Web1/Program.cs +++ b/src/samples/aspnet/Elsa.Samples.Web1/Program.cs @@ -9,6 +9,7 @@ using Elsa.Management.Extensions; using Elsa.Mediator.Extensions; using Elsa.Modules.AzureServiceBus.Activities; using Elsa.Modules.AzureServiceBus.Extensions; +using Elsa.Modules.Hangfire.Services; using Elsa.Modules.Http; using Elsa.Modules.Http.Extensions; using Elsa.Modules.JavaScript.Activities; @@ -43,7 +44,7 @@ services .AddProtoActorWorkflowHost() .IndexWorkflowTriggers() .AddElsaManagement() - .AddJobs(new QuartzSchedulingServiceProvider()) + .AddJobs(new QuartzJobSchedulerProvider(), new HangfireJobQueueProvider()) .AddHttpActivityServices() .AddJobServices() .AddAzureServiceBusServices(options => configuration.GetSection("AzureServiceBus").Bind(options))