如何包装 Hangfire 取消令牌?
How to wrap a Hangfire cancellation token?
我正在构建一个需要后台任务 运行 的 .net 核心 Web 应用程序。为了避免使用外部 cron 触发器,我们决定使用 Hangfire;这是一个漂亮的包,可以完全满足需要,然后就可以使用了;-)
为了保持清洁,我试图坚持 Uncle Bob 的清洁架构原则,并尽可能将我的 ApplicationCore 与基础架构分开。由于 Hangfire 是一个实现细节,理想情况下它应该位于基础设施项目中,与数据库访问、消息队列等一起,在 ApplicationCore 中有一个接口,我的域可以使用。
对于基本客户端 运行ning 循环和后台作业,这已经相当简单了,我最终将其作为我的 Interface
namespace ApplicationCore.Interfaces
{
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
public interface IBackgroundJobClient
{
void AddOrUpdate<T>(
string recurringJobId,
Expression<Func<T, Task>> methodCall,
string cronExpression);
void RemoveIfExists(string recurringJobId);
}
}
实现是这些方法的简单包装器,它使用 RecurringJob
namespace Infrastructure.BackgroundJobs
{
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Hangfire;
using IBackgroundJobClient = ApplicationCore.Interfaces.IBackgroundJobClient;
public class HangfireBackgroundJobClient : IBackgroundJobClient
{
public void AddOrUpdate<T>(
string recurringJobId,
Expression<Func<T, Task>> methodCall,
string cronExpression)
{
RecurringJob.AddOrUpdate<T>(recurringJobId, methodCall, cronExpression);
}
public void RemoveIfExists(string recurringJobId)
{
RecurringJob.RemoveIfExists(recurringJobId);
}
}
我遇到的问题是需要使用提供的 cancellationToken 设置 RecurringJob
。但是,如果不在我的 ApplicationCore 代码中公开底层 IJobCancellationToken
和 JobCancellationToken
对象,我看不到一种简单的方法...?
我目前得到的是基础设施中 JobCancellationToken
的包装器。
namespace Infrastructure.BackgroundJobs
{
public class BackgroundJobCancellationToken : JobCancellationToken
{
public BackgroundJobCancellationToken(bool canceled): base(canceled)
{
}
}
}
我的 ApplicationCore 中的一个接口,它复制了 Hangfire 接口。
namespace ApplicationCore.Interfaces
{
using System.Threading;
public interface IJobCancellationToken
{
CancellationToken ShutdownToken { get; }
void ThrowIfCancellationRequested();
}
}
然后我想作为作业执行的方法使用它,利用 cancellationToken.ShutdownToken
传递到需要 cancellationToken 的其他方法。
public async Task GenerateSubmission(Guid SetupGuidId, IJobCancellationToken cancellationToken)
{
try
{
// Sort out the entities that we'll need
var setup = await this.SetupRepository.GetByGuidIdAsync(SetupGuidId);
var forecast = await this.GetCurrentForecastForSetup(setup, DateTime.UtcNow, cancellationToken.ShutdownToken);
// Other Code
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
这又可以通过调用
在别处启用
public async Task<Setup> EnableSetup(Setup setup)
{
setup.Enable();
this.jobClient
.AddOrUpdate<IForecastService>(
setup.GuidId.ToString(),
f => f.GenerateSubmission(setup.GuidId, null),
"45 */2 * * *");
await this.setupRepository.UpdateAsync(setup);
return setup;
}
这应该通过 DomainEvents 和 Handlers 来完成,但是一次一个步骤:-)
有没有一种更干净、更好、更简单的方法,而不直接依赖我的 ApplicationCore 中的 Hangfire?
如果上述设置有效,我将对这个问题发表评论。
从 Hangfire 1.7 开始,您不再需要依赖 IJobCancellationToken
。您可以简单地使用标准的 .NET CancellationToken
。
我正在构建一个需要后台任务 运行 的 .net 核心 Web 应用程序。为了避免使用外部 cron 触发器,我们决定使用 Hangfire;这是一个漂亮的包,可以完全满足需要,然后就可以使用了;-)
为了保持清洁,我试图坚持 Uncle Bob 的清洁架构原则,并尽可能将我的 ApplicationCore 与基础架构分开。由于 Hangfire 是一个实现细节,理想情况下它应该位于基础设施项目中,与数据库访问、消息队列等一起,在 ApplicationCore 中有一个接口,我的域可以使用。
对于基本客户端 运行ning 循环和后台作业,这已经相当简单了,我最终将其作为我的 Interface
namespace ApplicationCore.Interfaces
{
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
public interface IBackgroundJobClient
{
void AddOrUpdate<T>(
string recurringJobId,
Expression<Func<T, Task>> methodCall,
string cronExpression);
void RemoveIfExists(string recurringJobId);
}
}
实现是这些方法的简单包装器,它使用 RecurringJob
namespace Infrastructure.BackgroundJobs
{
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Hangfire;
using IBackgroundJobClient = ApplicationCore.Interfaces.IBackgroundJobClient;
public class HangfireBackgroundJobClient : IBackgroundJobClient
{
public void AddOrUpdate<T>(
string recurringJobId,
Expression<Func<T, Task>> methodCall,
string cronExpression)
{
RecurringJob.AddOrUpdate<T>(recurringJobId, methodCall, cronExpression);
}
public void RemoveIfExists(string recurringJobId)
{
RecurringJob.RemoveIfExists(recurringJobId);
}
}
我遇到的问题是需要使用提供的 cancellationToken 设置 RecurringJob
。但是,如果不在我的 ApplicationCore 代码中公开底层 IJobCancellationToken
和 JobCancellationToken
对象,我看不到一种简单的方法...?
我目前得到的是基础设施中 JobCancellationToken
的包装器。
namespace Infrastructure.BackgroundJobs
{
public class BackgroundJobCancellationToken : JobCancellationToken
{
public BackgroundJobCancellationToken(bool canceled): base(canceled)
{
}
}
}
我的 ApplicationCore 中的一个接口,它复制了 Hangfire 接口。
namespace ApplicationCore.Interfaces
{
using System.Threading;
public interface IJobCancellationToken
{
CancellationToken ShutdownToken { get; }
void ThrowIfCancellationRequested();
}
}
然后我想作为作业执行的方法使用它,利用 cancellationToken.ShutdownToken
传递到需要 cancellationToken 的其他方法。
public async Task GenerateSubmission(Guid SetupGuidId, IJobCancellationToken cancellationToken)
{
try
{
// Sort out the entities that we'll need
var setup = await this.SetupRepository.GetByGuidIdAsync(SetupGuidId);
var forecast = await this.GetCurrentForecastForSetup(setup, DateTime.UtcNow, cancellationToken.ShutdownToken);
// Other Code
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
这又可以通过调用
在别处启用 public async Task<Setup> EnableSetup(Setup setup)
{
setup.Enable();
this.jobClient
.AddOrUpdate<IForecastService>(
setup.GuidId.ToString(),
f => f.GenerateSubmission(setup.GuidId, null),
"45 */2 * * *");
await this.setupRepository.UpdateAsync(setup);
return setup;
}
这应该通过 DomainEvents 和 Handlers 来完成,但是一次一个步骤:-)
有没有一种更干净、更好、更简单的方法,而不直接依赖我的 ApplicationCore 中的 Hangfire?
如果上述设置有效,我将对这个问题发表评论。
从 Hangfire 1.7 开始,您不再需要依赖 IJobCancellationToken
。您可以简单地使用标准的 .NET CancellationToken
。