Refactor Quartz module and add Hangfire provider for JobQueue service
This commit is contained in:
parent
f5aeaf9120
commit
fc5f14a18e
|
|
@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
|
||||
namespace Elsa.Jobs.Contracts;
|
||||
|
||||
public interface ISchedulingServiceProvider
|
||||
public interface IJobQueueProvider
|
||||
{
|
||||
void ConfigureServices(IServiceCollection services);
|
||||
}
|
||||
8
src/core/Elsa.Jobs/Contracts/IJobSchedulerProvider.cs
Normal file
8
src/core/Elsa.Jobs/Contracts/IJobSchedulerProvider.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Jobs.Contracts;
|
||||
|
||||
public interface IJobSchedulerProvider
|
||||
{
|
||||
void ConfigureServices(IServiceCollection services);
|
||||
}
|
||||
7
src/core/Elsa.Jobs/Contracts/IJobSerializer.cs
Normal file
7
src/core/Elsa.Jobs/Contracts/IJobSerializer.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
namespace Elsa.Jobs.Contracts;
|
||||
|
||||
public interface IJobSerializer
|
||||
{
|
||||
string Serialize(IJob job);
|
||||
T Deserialize<T>(string json) where T : IJob;
|
||||
}
|
||||
|
|
@ -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<IJobRunner, JobRunner>();
|
||||
services
|
||||
.AddSingleton<IJobSerializer, JobSerializer>()
|
||||
.AddSingleton<IJobRunner, JobRunner>();
|
||||
|
||||
serviceProvider.ConfigureServices(services);
|
||||
schedulerProvider.ConfigureServices(services);
|
||||
queueProvider.ConfigureServices(services);
|
||||
return services;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Hangfire.Core" Version="1.7.28" />
|
||||
<PackageReference Include="Hangfire" Version="1.7.28" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,4 @@ namespace Elsa.Modules.Hangfire.Extensions;
|
|||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers both Hangfire and Elsa specific services.
|
||||
/// If you register Hangfire yourself, use <see cref="ConfigureHangfireModule"/>
|
||||
/// </summary>
|
||||
public static IServiceCollection AddHangfireAndModule(this IServiceCollection services)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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<IJobQueue, HangfireJobQueue>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using Elsa.Jobs.Contracts;
|
||||
|
||||
namespace Elsa.Modules.Quartz.Contracts;
|
||||
|
||||
public interface IElsaJobSerializer
|
||||
{
|
||||
string Serialize(IJob job);
|
||||
T Deserialize<T>(string json) where T : IJob;
|
||||
}
|
||||
|
|
@ -16,4 +16,8 @@
|
|||
<ProjectReference Include="..\Elsa.Modules.Scheduling\Elsa.Modules.Scheduling.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Contracts" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers both Quartz as well as Elsa-specific services and jobs.
|
||||
/// If you register Quartz yourself, use <see cref="AddQuartzModule"/> instead.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddQuartzAndModule(
|
||||
this IServiceCollection services,
|
||||
Action<QuartzOptions>? configureQuartzOptions = default,
|
||||
Action<IServiceCollectionQuartzConfigurator>? configureQuartz = default,
|
||||
Action<QuartzHostedServiceOptions>? configureQuartzHostedService = default)
|
||||
{
|
||||
if (configureQuartzOptions != null)
|
||||
services.Configure(configureQuartzOptions);
|
||||
|
||||
return services
|
||||
.AddQuartz(configure =>
|
||||
{
|
||||
ConfigureQuartz(configure, configureQuartz);
|
||||
AddQuartzModule(services, configure);
|
||||
})
|
||||
.AddQuartzHostedService(options => ConfigureQuartzHostedService(options, configureQuartzHostedService));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <see cref="AddQuartzAndModule"/> to register & configure Quartz for Elsa.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddQuartzModule(this IServiceCollection services, IServiceCollectionQuartzConfigurator quartz)
|
||||
{
|
||||
services
|
||||
.AddSingleton<IElsaJobSerializer, ElsaJobSerializer>()
|
||||
.AddSingleton<IJobScheduler, QuartzJobScheduler>();
|
||||
|
||||
quartz.AddElsaJobs();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IServiceCollectionQuartzConfigurator AddElsaJobs(this IServiceCollectionQuartzConfigurator quartz)
|
||||
public static IServiceCollectionQuartzConfigurator AddElsaJobs(this IServiceCollectionQuartzConfigurator quartz)
|
||||
{
|
||||
quartz.AddJob<RunWorkflowJob>();
|
||||
quartz.AddJob<ResumeWorkflowJob>();
|
||||
|
|
@ -55,20 +15,6 @@ public static class ServiceCollectionExtensions
|
|||
return quartz;
|
||||
}
|
||||
|
||||
private static void ConfigureQuartzHostedService(QuartzHostedServiceOptions options, Action<QuartzHostedServiceOptions>? configureQuartzHostedService)
|
||||
{
|
||||
options.WaitForJobsToComplete = true;
|
||||
configureQuartzHostedService?.Invoke(options);
|
||||
}
|
||||
|
||||
private static IServiceCollectionQuartzConfigurator AddJob<TJob>(this IServiceCollectionQuartzConfigurator quartz) where TJob : IJob =>
|
||||
quartz.AddJob<QuartzJob<TJob>>(job => job.StoreDurably().WithIdentity(typeof(TJob).Name));
|
||||
|
||||
private static void ConfigureQuartz(IServiceCollectionQuartzConfigurator quartz, Action<IServiceCollectionQuartzConfigurator>? configureQuartz)
|
||||
{
|
||||
quartz.UseMicrosoftDependencyInjectionJobFactory();
|
||||
quartz.UseSimpleTypeLoader();
|
||||
quartz.UseInMemoryStore();
|
||||
configureQuartz?.Invoke(quartz);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
|||
/// <typeparam name="TElsaJob"></typeparam>
|
||||
public class QuartzJob<TElsaJob> : 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<TElsaJob>(json);
|
||||
var elsaJob = _jobSerializer.Deserialize<TElsaJob>(json);
|
||||
await _jobRunner.RunJobAsync(elsaJob, context.CancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<QuartzJobScheduler> logger)
|
||||
public QuartzJobScheduler(IJobSerializer jobSerializer, ISchedulerFactory schedulerFactory, ILogger<QuartzJobScheduler> 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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
using Elsa.Jobs.Contracts;
|
||||
using Elsa.Modules.Quartz.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Quartz;
|
||||
|
||||
namespace Elsa.Modules.Quartz.Services;
|
||||
|
||||
/// <summary>
|
||||
/// A Quartz.NET implementation for <see cref="IJobSchedulerProvider"/>.
|
||||
/// </summary>
|
||||
public class QuartzJobSchedulerProvider : IJobSchedulerProvider
|
||||
{
|
||||
public QuartzJobSchedulerProvider(bool registerQuartz = true)
|
||||
{
|
||||
RegisterQuartz = registerQuartz;
|
||||
}
|
||||
|
||||
public QuartzJobSchedulerProvider(Action<QuartzOptions> configureQuartzOptions)
|
||||
{
|
||||
RegisterQuartz = true;
|
||||
ConfigureQuartzOptions = configureQuartzOptions;
|
||||
}
|
||||
|
||||
public QuartzJobSchedulerProvider(
|
||||
Action<QuartzOptions> configureQuartzOptions,
|
||||
Action<IServiceCollectionQuartzConfigurator> configureQuartz)
|
||||
{
|
||||
RegisterQuartz = true;
|
||||
ConfigureQuartzOptions = configureQuartzOptions;
|
||||
ConfigureQuartz = configureQuartz;
|
||||
}
|
||||
|
||||
public QuartzJobSchedulerProvider(
|
||||
Action<QuartzOptions> configureQuartzOptions,
|
||||
Action<IServiceCollectionQuartzConfigurator> configureQuartz,
|
||||
Action<QuartzHostedServiceOptions> configureQuartzHostedService)
|
||||
{
|
||||
RegisterQuartz = true;
|
||||
ConfigureQuartzOptions = configureQuartzOptions;
|
||||
ConfigureQuartz = configureQuartz;
|
||||
ConfigureQuartzHostedService = configureQuartzHostedService;
|
||||
}
|
||||
|
||||
public bool RegisterQuartz { get; set; }
|
||||
public Action<QuartzOptions>? ConfigureQuartzOptions { get; set; }
|
||||
public Action<IServiceCollectionQuartzConfigurator>? ConfigureQuartz { get; set; }
|
||||
public Action<QuartzHostedServiceOptions>? 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<IJobScheduler, QuartzJobScheduler>();
|
||||
|
||||
}
|
||||
|
||||
private static void ConfigureQuartzInternal(IServiceCollectionQuartzConfigurator quartz, Action<IServiceCollectionQuartzConfigurator>? configureQuartz)
|
||||
{
|
||||
quartz.UseMicrosoftDependencyInjectionJobFactory();
|
||||
quartz.UseSimpleTypeLoader();
|
||||
quartz.UseInMemoryStore();
|
||||
configureQuartz?.Invoke(quartz);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\modules\Elsa.Modules.AzureServiceBus\Elsa.Modules.AzureServiceBus.csproj" />
|
||||
<ProjectReference Include="..\..\..\modules\Elsa.Modules.Hangfire\Elsa.Modules.Hangfire.csproj" />
|
||||
<ProjectReference Include="..\..\..\modules\Elsa.Modules.Http\Elsa.Modules.Http.csproj" />
|
||||
<ProjectReference Include="..\..\..\modules\Elsa.Modules.JavaScript\Elsa.Modules.JavaScript.csproj" />
|
||||
<ProjectReference Include="..\..\..\modules\Elsa.Modules.Scheduling\Elsa.Modules.Scheduling.csproj" />
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Reference in a new issue