Как обернуть токен отмены Hangfire?

#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.