#domain-driven-design #hangfire #clean-architecture #cancellation-token
#дизайн, управляемый доменом #hangfire #чистая архитектура #отмена-токен
Вопрос:
Я создаю веб-приложение .net core, для которого требуется выполнение фоновых задач. Чтобы избежать использования внешних триггеров cron, мы решили использовать Hangfire; это прекрасный пакет для использования, он делает именно то, что нужно, а затем убирается с дороги 😉
Чтобы поддерживать чистоту, я стараюсь придерживаться принципов чистой архитектуры дяди Боба и как можно больше отделять свое ядро приложения от инфраструктуры. Поскольку Hangfire является деталью реализации, в идеале он должен находиться в проекте инфраструктуры, наряду с доступом к базе данных, очередями сообщений и т. Д. с интерфейсом в ApplicationCore, который может использовать мой домен.
Для базового клиента, выполняющего повторяющиеся и фоновые задания, это было довольно просто сделать, и в итоге я получил это в качестве своего 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);
}
}
Проблема, с которой я сталкиваюсь, заключается в необходимости настройки a RecurringJob
с помощью предоставленного CancellationToken. Однако я не вижу простого способа сделать это, не раскрывая базовые IJobCancellationToken
JobCancellationToken
объекты и в моем коде ApplicationCore …?
В настоящее время у меня есть оболочка для 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 и обработчиков, но шаг за шагом 🙂
Есть ли более чистый, лучший и простой способ сделать это без прямой зависимости от Hangfire в моем ApplicationCore?
Если вышеуказанная настройка сработает, я оставлю комментарий по этому вопросу.
Комментарии:
1. Поскольку ваш IJobCancellationToken определен в ApplicationCore, я не понимаю, как логика вашего приложения зависит от hangfire?
Ответ №1:
Начиная с Hangfire 1.7, вам больше не нужно полагаться на IJobCancellationToken
. Вместо этого вы можете просто использовать стандартный . CancellationToken
NET.