diff --git a/docs/en/Background-Workers-Hangfire.md b/docs/en/Background-Workers-Hangfire.md new file mode 100644 index 0000000000..e1e6fc71ad --- /dev/null +++ b/docs/en/Background-Workers-Hangfire.md @@ -0,0 +1,99 @@ +# Hangfire Background Worker Manager + +[Hangfire](https://https://www.hangfire.io/) is an advanced background jobs and worker manager. You can integrate Hangfire with the ABP Framework to use it instead of the [default background worker manager](Background-Workers.md). + +The major advantage is that you can use the same server farm to manage your Background Jobs and Workers, as well as leverage the advanced scheduling that is available from Hangfire for [Recurring Jobs](https://docs.hangfire.io/en/latest/background-methods/performing-recurrent-tasks.html?highlight=recurring), aka Background Workers. + +## Installation + +It is suggested to use the [ABP CLI](CLI.md) to install this package. + +### Using the ABP CLI + +Open a command line window in the folder of the project (.csproj file) and type the following command: + +````bash +abp add-package Volo.Abp.BackgroundWorkers.Hangfire +```` + +### Manual Installation + +If you want to manually install; + +1. Add the [Volo.Abp.BackgroundWorkers.Hangfire](https://www.nuget.org/packages/Volo.Abp.BackgroundWorkers.Hangfire) NuGet package to your project: + + ```` + Install-Package Volo.Abp.BackgroundWorkers.Hangfire + ```` + +2. Add the `AbpBackgroundWorkersHangfireModule` to the dependency list of your module: + +````csharp +[DependsOn( + //...other dependencies + typeof(AbpBackgroundWorkersHangfireModule) //Add the new module dependency + )] +public class YourModule : AbpModule +{ +} +```` + +> Hangfire background worker integration provides an adapter `HangfirePeriodicBackgroundWorkerAdapter` to automatically load any `PeriodicBackgroundWorkerBase` and `AsyncPeriodicBackgroundWorkerBase` derived classes as `IHangfireBackgroundWorker` instances. This allows you to still to easily switch over to use Hangfire as the background manager even you have existing background workers that are based on the [default background workers implementation](Background-Workers.md). + +## Create a Background Worker + +`HangfireBackgroundWorkerBase` is an easy way to create a background worker. + +```` csharp +public class MyLogWorker : HangfireBackgroundWorkerBase +{ + public MyLogWorker() + { + RecurringJobId = nameof(MyLogWorker); + CronExpression = Cron.Daily(); + } + + public override Task DoWorkAsync() + { + Logger.LogInformation("Executed MyLogWorker..!"); + return Task.CompletedTask; + } +} +```` + +* **RecurringJobId** Is an optional parameter, see [Hangfire document](https://docs.hangfire.io/en/latest/background-methods/performing-recurrent-tasks.html) +* **CronExpression** Is a CRON expression, see [CRON expression](https://en.wikipedia.org/wiki/Cron#CRON_expression) + +> You can directly implement the `IHangfireBackgroundWorker`, but `HangfireBackgroundWorkerBase` provides some useful properties like Logger. + +## Register BackgroundWorkerManager + +After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class: + +```` csharp +[DependsOn(typeof(AbpBackgroundWorkersModule))] +public class MyModule : AbpModule +{ + public override void OnApplicationInitialization( + ApplicationInitializationContext context) + { + context.AddBackgroundWorker(); + } +} +```` + +`context.AddBackgroundWorker(...)` is a shortcut extension method for the expression below: + +```` csharp +context.ServiceProvider + .GetRequiredService() + .Add( + context + .ServiceProvider + .GetRequiredService() + ); +```` + +So, it resolves the given background worker and adds to the `IBackgroundWorkerManager`. + +While we generally add workers in OnApplicationInitialization, there are no restrictions on that. You can inject IBackgroundWorkerManager anywhere and add workers at runtime. Background worker manager will stop and release all the registered workers when your application is being shut down. \ No newline at end of file diff --git a/docs/en/Background-Workers.md b/docs/en/Background-Workers.md index b12f1881fb..0c9e26e409 100644 --- a/docs/en/Background-Workers.md +++ b/docs/en/Background-Workers.md @@ -131,10 +131,15 @@ If that's a problem for your workers, you have two options; * Disable the background worker system using the `AbpBackgroundWorkerOptions` described above, for all the application instances, except one of them. * Disable the background worker system for all the application instances and create another special application that runs on a single server and execute the workers. -## Quartz Integration +## Integrations -ABP Framework's background worker system is good to implement periodic tasks. However, you may want to use an advanced task scheduler like [Quartz](https://www.quartz-scheduler.net/). See the community contributed [quartz integration](Background-Workers-Quartz.md) for the background workers. +Background worker system is extensible and you can change the default background worker manager with your own implementation or on of the pre-built integrations. + +See pre-built worker manager alternatives: + +* [Quartz Background Worker Manager](Background-Workers-Quartz.md) +* [Hangfire Background Worker Manager](Background-Workers-Hangfire.md) ## See Also -* [Quartz Integration for the background workers](Background-Workers-Quartz.md) + * [Background Jobs](Background-Jobs.md) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 6bffa3d5ec..8f97d1147c 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -235,6 +235,10 @@ { "text": "Quartz Integration", "path": "Background-Workers-Quartz.md" + }, + { + "text": "Hangfire Integration", + "path": "Background-Workers-Hangfire.md" } ] }, diff --git a/docs/zh-Hans/Background-Workers-Hangfire.md b/docs/zh-Hans/Background-Workers-Hangfire.md new file mode 100644 index 0000000000..bd63ff91e9 --- /dev/null +++ b/docs/zh-Hans/Background-Workers-Hangfire.md @@ -0,0 +1,100 @@ +# Hangfire Background Worker Manager + +[Hangfire](https://https://www.hangfire.io/)是一个高级的后台工作者管理. 你可以用ABP框架Hangfire集成代替[默认后台工作者管理](Background-Workers.md). + +主要优点是你可以使用相同的服务器群来管理你的后台作业和工作线程以及利用 Hangfire 提供的[Recurring Jobs](https://docs.hangfire.io/en/latest/background-methods/performing-recurrent-tasks.html?highlight=recurring)高级调度功能. + +## 安装 + +建议使用[ABP CLI](CLI.md)安装包. + + +### 使用ABP CLI + +在项目的文件夹(.csproj文件)中打开命令行窗口输入以下命令: + +````bash +abp add-package Volo.Abp.BackgroundWorkers.Hangfire +```` + +### 手动安装 + +如果你想手动安装; + +1. 添加 [Volo.Abp.BackgroundWorkers.Hangfire](https://www.nuget.org/packages/Volo.Abp.BackgroundWorkers.Hangfire) NuGet包添加到你的项目: + + ```` + Install-Package Volo.Abp.BackgroundWorkers.Hangfire + ```` + +2. 添加 `AbpBackgroundWorkersHangfireModule` 到你的模块的依赖列表: + +````csharp +[DependsOn( + //...other dependencies + typeof(AbpBackgroundWorkersHangfireModule) //Add the new module dependency + )] +public class YourModule : AbpModule +{ +} +```` + +> Hangfire后台工作者集成提供了 `HangfirePeriodicBackgroundWorkerAdapter` 来适配 `PeriodicBackgroundWorkerBase` 和 `AsyncPeriodicBackgroundWorkerBase` 派生类. 所以你依然可以按照[后台工作者文档](Background-Workers.md)来定义后台作业. + +## 创建后台工作者 + +`HangfireBackgroundWorkerBase` 是创建一个后台工作者简单的方法. + +```` csharp +public class MyLogWorker : HangfireBackgroundWorkerBase +{ + public MyLogWorker() + { + RecurringJobId = nameof(MyLogWorker); + CronExpression = Cron.Daily(); + } + + public override Task DoWorkAsync() + { + Logger.LogInformation("Executed MyLogWorker..!"); + return Task.CompletedTask; + } +} +```` + +* **RecurringJobId** 是一个可选参数, 参阅 [Hangfire文档](https://docs.hangfire.io/en/latest/background-methods/performing-recurrent-tasks.html) +* **CronExpression** 是CRON表达式, 参阅 [CRON 表达式](https://en.wikipedia.org/wiki/Cron#CRON_expression) + +> 你可以直接实现 `IHangfireBackgroundWorker`, 但是 `HangfireBackgroundWorkerBase` 提供了一些有用的属性,例如 `Logger`. + +## 注册到后台工作者管理器 + +创建一个后台工作者后, 你应该添加到 `IBackgroundWorkerManager`, 最常用的地方是在你模块类的 `OnApplicationInitialization` 方法中: + +```` csharp +[DependsOn(typeof(AbpBackgroundWorkersModule))] +public class MyModule : AbpModule +{ + public override void OnApplicationInitialization( + ApplicationInitializationContext context) + { + context.AddBackgroundWorker(); + } +} +```` + +`context.AddBackgroundWorker(...)` 是一个是以下代码快捷的扩展方法: + +```` csharp +context.ServiceProvider + .GetRequiredService() + .Add( + context + .ServiceProvider + .GetRequiredService() + ); +```` + +它解析给定的后台工作者并添加到 `IBackgroundWorkerManager`. + +虽然我们通常在 `OnApplicationInitialization` 中添加后台工作者, 但对此没有限制. 你可以在任何地方注入 `IBackgroundWorkerManager` 并在运行时添加后台工作者. \ No newline at end of file diff --git a/docs/zh-Hans/Background-Workers.md b/docs/zh-Hans/Background-Workers.md index 26bafed2da..a7563349ab 100644 --- a/docs/zh-Hans/Background-Workers.md +++ b/docs/zh-Hans/Background-Workers.md @@ -128,11 +128,13 @@ context.ServiceProvider * 使用上面提到的 `AbpBackgroundWorkerOptions` 禁用其他的后台工作者系统,只保留一个实例. * 所有的应用程序都禁用后台工作者系统,创建一个特殊的应用程序在一个服务上运行执行工作者. -## Quartz 集成 +## 集成 -ABP框架的后台工作者系统可以很好的执行周期任务. 但是你可能需要使用更高级的任务调度,像[Quartz](https://www.quartz-scheduler.net/). 参阅社区贡献的[Quartz集成](Background-Workers-Quartz.md) +后台工作者系统是可扩展的,你可以更改默认的后台工作者管理器为你自己的实现,或者使用以下预构建的集成: + +* [Quartz 后台工作者管理器](Background-Workers-Quartz.md) +* [Hangfire 后台工作者管理器](Background-Workers-Hangfire.md) ## 另请参阅 -* [后台工作者的Quartz集成](Background-Workers-Quartz.md) * [后台作业](Background-Jobs.md) \ No newline at end of file diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 15a770e023..37f57388c0 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -176,6 +176,10 @@ { "text": "Quartz 集成", "path": "Background-Workers-Quartz.md" + }, + { + "text": "Hangfire 集成", + "path": "Background-Workers-Hangfire.md" } ] } diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 309be85ea1..991d1d08d5 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -372,6 +372,7 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AzureServiceBus", "src\Volo.Abp.AzureServiceBus\Volo.Abp.AzureServiceBus.csproj", "{808EC18E-C8CC-4F5C-82B6-984EADBBF85D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus.Azure", "src\Volo.Abp.EventBus.Azure\Volo.Abp.EventBus.Azure.csproj", "{FB27F78E-F10E-4810-9B8E-BCD67DCFC8A2}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Authorization.Abstractions", "src\Volo.Abp.Authorization.Abstractions\Volo.Abp.Authorization.Abstractions.csproj", "{87B0C2A8-FE95-4779-8B9C-2181AA52B3FA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Core", "src\Volo.Abp.TextTemplating.Core\Volo.Abp.TextTemplating.Core.csproj", "{184E859A-282D-44D7-B8E9-FEA874644013}" @@ -393,10 +394,13 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus.Boxes", "src\Volo.Abp.EventBus.Boxes\Volo.Abp.EventBus.Boxes.csproj", "{6E289F31-7924-418B-9DAC-62A7CFADF916}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.DistributedLocking", "src\Volo.Abp.DistributedLocking\Volo.Abp.DistributedLocking.csproj", "{9A7EEA08-15BE-476D-8168-53039867038E}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Auditing.Contracts", "src\Volo.Abp.Auditing.Contracts\Volo.Abp.Auditing.Contracts.csproj", "{508B6355-AD28-4E60-8549-266D21DBF2CF}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http.Client.Web", "src\Volo.Abp.Http.Client.Web\Volo.Abp.Http.Client.Web.csproj", "{F7407459-8AFA-45E4-83E9-9BB01412CC08}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BackgroundWorkers.Hangfire", "src\Volo.Abp.BackgroundWorkers.Hangfire\Volo.Abp.BackgroundWorkers.Hangfire.csproj", "{E5FCE710-C5A3-4F94-B9C9-BD1E99252BFB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1187,6 +1191,10 @@ Global {F7407459-8AFA-45E4-83E9-9BB01412CC08}.Debug|Any CPU.Build.0 = Debug|Any CPU {F7407459-8AFA-45E4-83E9-9BB01412CC08}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7407459-8AFA-45E4-83E9-9BB01412CC08}.Release|Any CPU.Build.0 = Release|Any CPU + {E5FCE710-C5A3-4F94-B9C9-BD1E99252BFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5FCE710-C5A3-4F94-B9C9-BD1E99252BFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5FCE710-C5A3-4F94-B9C9-BD1E99252BFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5FCE710-C5A3-4F94-B9C9-BD1E99252BFB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1388,6 +1396,7 @@ Global {9A7EEA08-15BE-476D-8168-53039867038E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {508B6355-AD28-4E60-8549-266D21DBF2CF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {F7407459-8AFA-45E4-83E9-9BB01412CC08} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {E5FCE710-C5A3-4F94-B9C9-BD1E99252BFB} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/FodyWeavers.xml b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/FodyWeavers.xml new file mode 100644 index 0000000000..bc5a74a236 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/FodyWeavers.xsd b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo.Abp.BackgroundWorkers.Hangfire.csproj b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo.Abp.BackgroundWorkers.Hangfire.csproj new file mode 100644 index 0000000000..fe87db9cd1 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo.Abp.BackgroundWorkers.Hangfire.csproj @@ -0,0 +1,22 @@ + + + + + + + netstandard2.0 + Volo.Abp.BackgroundWorkers.Hangfire + Volo.Abp.BackgroundWorkers.Hangfire + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/AbpBackgroundWorkersHangfireModule.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/AbpBackgroundWorkersHangfireModule.cs new file mode 100644 index 0000000000..4efbdcffb7 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/AbpBackgroundWorkersHangfireModule.cs @@ -0,0 +1,36 @@ +using System; +using Hangfire; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Hangfire; +using Volo.Abp.Modularity; + +namespace Volo.Abp.BackgroundWorkers.Hangfire +{ + [DependsOn( + typeof(AbpBackgroundWorkersModule), + typeof(AbpHangfireModule))] + public class AbpBackgroundWorkerHangfireModule : AbpModule + { + public override void OnPreApplicationInitialization(ApplicationInitializationContext context) + { + var options = context.ServiceProvider.GetRequiredService>().Value; + if (!options.IsEnabled) + { + var hangfireOptions = context.ServiceProvider.GetRequiredService>().Value; + hangfireOptions.BackgroundJobServerFactory = CreateOnlyEnqueueJobServer; + } + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddSingleton(typeof(HangfirePeriodicBackgroundWorkerAdapter<>)); + } + + private BackgroundJobServer CreateOnlyEnqueueJobServer(IServiceProvider serviceProvider) + { + serviceProvider.GetRequiredService(); + return null; + } + } +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerBase.cs new file mode 100644 index 0000000000..230e9577a3 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerBase.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.BackgroundWorkers.Hangfire +{ + public abstract class HangfireBackgroundWorkerBase : BackgroundWorkerBase, IHangfireBackgroundWorker + { + public string RecurringJobId { get; set; } + + public string CronExpression { get; set; } + + public abstract Task DoWorkAsync(); + } +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs new file mode 100644 index 0000000000..bf613f6835 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs @@ -0,0 +1,91 @@ +using System; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Hangfire; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace Volo.Abp.BackgroundWorkers.Hangfire +{ + [Dependency(ReplaceServices = true)] + public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDependency + { + public Task StartAsync(CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + + public void Add(IBackgroundWorker worker) + { + if (worker is IHangfireBackgroundWorker hangfireBackgroundWorker) + { + if (hangfireBackgroundWorker.RecurringJobId.IsNullOrWhiteSpace()) + { + RecurringJob.AddOrUpdate(() => hangfireBackgroundWorker.DoWorkAsync(), + hangfireBackgroundWorker.CronExpression); + } + else + { + RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId,() => hangfireBackgroundWorker.DoWorkAsync(), + hangfireBackgroundWorker.CronExpression); + } + } + else + { + int? period; + + if (worker is AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase) + { + var timer = (AbpTimer) worker.GetType() + .GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); + period = timer?.Period; + } + else + { + return; + } + + if (period == null) + { + return; + } + + var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(worker.GetType()); + var workerAdapter = Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker; + + RecurringJob.AddOrUpdate(() => workerAdapter.DoWorkAsync(), GetCron(period.Value)); + } + } + + protected virtual string GetCron(int period) + { + var time = TimeSpan.FromMilliseconds(period); + string cron; + + if (time.TotalSeconds <= 59) + { + cron = $"*/{time.TotalSeconds} * * * * *"; + } + else if (time.TotalMinutes <= 59) + { + cron = $"*/{time.TotalMinutes} * * * *"; + } + else if (time.TotalHours <= 23) + { + cron = $"0 */{time.TotalHours} * * *"; + } + else + { + cron = $"0 0 */{time.TotalDays} * *"; + } + + return cron; + } + } +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfirePeriodicBackgroundWorkerAdapter.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfirePeriodicBackgroundWorkerAdapter.cs new file mode 100644 index 0000000000..2f7dc02757 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfirePeriodicBackgroundWorkerAdapter.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; + +namespace Volo.Abp.BackgroundWorkers.Hangfire +{ + public class HangfirePeriodicBackgroundWorkerAdapter : HangfireBackgroundWorkerBase + where TWorker : IBackgroundWorker + { + private readonly MethodInfo _doWorkAsyncMethod; + private readonly MethodInfo _doWorkMethod; + + public HangfirePeriodicBackgroundWorkerAdapter() + { + _doWorkAsyncMethod = + typeof(TWorker).GetMethod("DoWorkAsync", BindingFlags.Instance | BindingFlags.NonPublic); + _doWorkMethod = typeof(TWorker).GetMethod("DoWork", BindingFlags.Instance | BindingFlags.NonPublic); + } + + public override async Task DoWorkAsync() + { + var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider); + var worker = ServiceProvider.GetRequiredService(); + + switch (worker) + { + case AsyncPeriodicBackgroundWorkerBase asyncPeriodicBackgroundWorker: + await (Task) _doWorkAsyncMethod.Invoke(asyncPeriodicBackgroundWorker, new object[] {workerContext}); + break; + case PeriodicBackgroundWorkerBase periodicBackgroundWorker: + _doWorkMethod.Invoke(periodicBackgroundWorker, new object[] {workerContext}); + break; + } + } + } +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/IHangfireBackgroundWorker.cs b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/IHangfireBackgroundWorker.cs new file mode 100644 index 0000000000..84518a6158 --- /dev/null +++ b/framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/IHangfireBackgroundWorker.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.BackgroundWorkers.Hangfire +{ + public interface IHangfireBackgroundWorker : IBackgroundWorker + { + string RecurringJobId { get; set; } + + string CronExpression { get; set; } + + Task DoWorkAsync(); + } +} + + diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 7d48c1ac1d..fd99c6a068 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -73,6 +73,7 @@ $projects = ( "framework/src/Volo.Abp.BackgroundJobs.Quartz", "framework/src/Volo.Abp.BackgroundWorkers", "framework/src/Volo.Abp.BackgroundWorkers.Quartz", + "framework/src/Volo.Abp.BackgroundWorkers.Hangfire", "framework/src/Volo.Abp.BlazoriseUI", "framework/src/Volo.Abp.BlobStoring", "framework/src/Volo.Abp.BlobStoring.FileSystem",