From 4b9907b0492a484dff2db30e19d6f9f8fe8434ff Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Mon, 21 Mar 2022 11:41:27 +0100 Subject: [PATCH] Implement Hangfire proxy job --- docker-compose.yml | 14 +++++++++++-- .../Extensions/ServiceCollectionExtensions.cs | 7 ------- .../Elsa.Modules.Hangfire/Jobs/RunElsaJob.cs | 21 +++++++++++++++++++ .../Services/HangfireJobQueue.cs | 5 ++--- .../Services/HangfireJobQueueProvider.cs | 13 +++++++++++- .../aspnet/Elsa.Samples.Web1/Program.cs | 5 ++++- .../aspnet/Elsa.Samples.Web1/appsettings.json | 3 ++- 7 files changed, 53 insertions(+), 15 deletions(-) delete mode 100644 src/modules/Elsa.Modules.Hangfire/Extensions/ServiceCollectionExtensions.cs create mode 100644 src/modules/Elsa.Modules.Hangfire/Jobs/RunElsaJob.cs diff --git a/docker-compose.yml b/docker-compose.yml index 3c1e24fac..e7e03b1b9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,18 +28,28 @@ services: - "8600:8600" - "8600:8600/udp" command: "agent -server -bootstrap-expect 3 -ui -client 0.0.0.0" + + sqlserver: + image: "mcr.microsoft.com/mssql/server:2019-latest" + ports: + - "3433:1433" + environment: + SA_PASSWORD: "Elsa2022!" + ACCEPT_EULA: "Y" + volumes: + - c:\data\docker\sqlserver2019:/var/opt/mssql/data mongodb: image: mongo:latest ports: - - 127.0.0.1:27017:27017 + - "127.0.0.1:27017:27017" volumes: - mongodb_data:/data/db redis: image: redis:latest ports: - - 127.0.0.1:6379:6379 + - "127.0.0.1:6379:6379" networks: consul: diff --git a/src/modules/Elsa.Modules.Hangfire/Extensions/ServiceCollectionExtensions.cs b/src/modules/Elsa.Modules.Hangfire/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 65a9e92a2..000000000 --- a/src/modules/Elsa.Modules.Hangfire/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Elsa.Modules.Hangfire.Extensions; - -public static class ServiceCollectionExtensions -{ -} \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Hangfire/Jobs/RunElsaJob.cs b/src/modules/Elsa.Modules.Hangfire/Jobs/RunElsaJob.cs new file mode 100644 index 000000000..218a68216 --- /dev/null +++ b/src/modules/Elsa.Modules.Hangfire/Jobs/RunElsaJob.cs @@ -0,0 +1,21 @@ +using Elsa.Jobs.Contracts; + +namespace Elsa.Modules.Hangfire.Jobs; + +/// +/// A generic Hangfire job that executes the specified Elsa job. Basically a proxy. +/// +public class RunElsaJob +{ + private readonly IJobRunner _jobRunner; + + public RunElsaJob(IJobRunner jobRunner) + { + _jobRunner = jobRunner; + } + + public async Task RunAsync(IJob job, CancellationToken cancellationToken) + { + await _jobRunner.RunJobAsync(job, cancellationToken); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueue.cs b/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueue.cs index ec13bc599..53cd40221 100644 --- a/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueue.cs +++ b/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueue.cs @@ -1,4 +1,5 @@ using Elsa.Jobs.Contracts; +using Elsa.Modules.Hangfire.Jobs; using Hangfire; using Hangfire.States; using HangfireJob = Hangfire.Common.Job; @@ -8,17 +9,15 @@ namespace Elsa.Modules.Hangfire.Services; public class HangfireJobQueue : IJobQueue { private readonly IBackgroundJobClient _backgroundJobClient; - private readonly IJobRunner _jobRunner; public HangfireJobQueue(IBackgroundJobClient backgroundJobClient, IJobRunner jobRunner) { _backgroundJobClient = backgroundJobClient; - _jobRunner = jobRunner; } public Task SubmitJobAsync(IJob job, string? queueName = default, CancellationToken cancellationToken = default) { - var hangfireJob = HangfireJob.FromExpression(x => _jobRunner.RunJobAsync(x, CancellationToken.None)); + var hangfireJob = HangfireJob.FromExpression(x => x.RunAsync(job, CancellationToken.None)); _backgroundJobClient.Create(hangfireJob, new EnqueuedState(queueName ?? "default")); return Task.CompletedTask; diff --git a/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueueProvider.cs b/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueueProvider.cs index 43f6dec40..51a3c5958 100644 --- a/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueueProvider.cs +++ b/src/modules/Elsa.Modules.Hangfire/Services/HangfireJobQueueProvider.cs @@ -2,6 +2,7 @@ using Elsa.Jobs.Contracts; using Hangfire; using Hangfire.SqlServer; using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; namespace Elsa.Modules.Hangfire.Services; @@ -23,6 +24,7 @@ public class HangfireJobQueueProvider : IJobQueueProvider public bool UseSqlServerStorage { get; set; } public string? SqlServerConnectionString { get; set; } public SqlServerStorageOptions? SqlServerStorageOptions { get; set; } + public Action? ConfigureBackgroundServerOptions { get; set; } public void ConfigureServices(IServiceCollection services) { @@ -31,13 +33,22 @@ public class HangfireJobQueueProvider : IJobQueueProvider services.AddHangfire(configuration => { configuration.UseSimpleAssemblyNameTypeSerializer(); - + configuration.UseRecommendedSerializerSettings(json => json.TypeNameHandling = TypeNameHandling.Objects); + if (UseSqlServerStorage) { var storageOptions = SqlServerStorageOptions ?? new SqlServerStorageOptions(); configuration.UseSqlServerStorage(SqlServerConnectionString, storageOptions); } }); + + if (UseSqlServerStorage) + services.AddHangfireServer((_, options) => ConfigureBackgroundServerOptions?.Invoke(options), new SqlServerStorage(SqlServerConnectionString)); + else + services.AddHangfireServer(options => + { + ConfigureBackgroundServerOptions?.Invoke(options); + }); } services.AddSingleton(); diff --git a/src/samples/aspnet/Elsa.Samples.Web1/Program.cs b/src/samples/aspnet/Elsa.Samples.Web1/Program.cs index 1485a2285..026385eea 100644 --- a/src/samples/aspnet/Elsa.Samples.Web1/Program.cs +++ b/src/samples/aspnet/Elsa.Samples.Web1/Program.cs @@ -37,6 +37,9 @@ var builder = WebApplication.CreateBuilder(args); var services = builder.Services; var configuration = builder.Configuration; +// Run the SqlServer container from docker-compose.yml to start a SQL Server container. +var sqlServerConnectionString = configuration.GetConnectionString("SqlServer"); + // Add services. services .AddElsa() @@ -45,7 +48,7 @@ services .AddProtoActorWorkflowHost() .IndexWorkflowTriggers() .AddElsaManagement() - .AddJobServices(new QuartzJobSchedulerProvider(), new HangfireJobQueueProvider()) + .AddJobServices(new QuartzJobSchedulerProvider(), new HangfireJobQueueProvider(sqlServerConnectionString)) .AddHttpActivityServices() .AddAzureServiceBusServices(options => configuration.GetSection("AzureServiceBus").Bind(options)) .ConfigureWorkflowRuntime(options => diff --git a/src/samples/aspnet/Elsa.Samples.Web1/appsettings.json b/src/samples/aspnet/Elsa.Samples.Web1/appsettings.json index 4d330878b..1dcdbfd5b 100644 --- a/src/samples/aspnet/Elsa.Samples.Web1/appsettings.json +++ b/src/samples/aspnet/Elsa.Samples.Web1/appsettings.json @@ -9,7 +9,8 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "AzureServiceBus": "" + "AzureServiceBus": "", + "SqlServer": "Server=localhost,3433;Database=Elsa3;User ID=sa;Password=Elsa2022!;MultipleActiveResultSets=True;Max Pool Size=500;Connection Timeout=3600;TrustServerCertificate=True" }, "AzureServiceBus": { "ConnectionStringOrName": "AzureServiceBus",