Comment planifier des travaux à l'aide de Quartz.NET dans ASP.NET Core

Lorsque vous travaillez sur des applications Web, vous devrez souvent exécuter certaines tâches en arrière-plan. Dans certains cas, ce seront des tâches qui doivent être exécutées à des intervalles de temps prédéfinis.

Quartz.NET est un port .NET open source du célèbre framework de planification de travaux Java. Il est utilisé depuis longtemps et fournit un excellent support pour travailler avec les expressions Cron. Vous pouvez en savoir plus sur Quartz.NET à partir d'un article précédent ici. 

Cet article présente une discussion sur la façon dont nous pouvons travailler avec Quartz.NET dans ASP.NET Core pour planifier des travaux en arrière-plan.

Pour utiliser les exemples de code fournis dans cet article, vous devez disposer de Visual Studio 2019 installé sur votre système. Si vous n'en avez pas déjà une copie, vous pouvez télécharger Visual Studio 2019 ici. 

Créer un projet d'API ASP.NET Core

Tout d'abord, créons un projet ASP.NET Core dans Visual Studio. En supposant que Visual Studio 2019 est installé sur votre système, suivez les étapes décrites ci-dessous pour créer un nouveau projet ASP.NET Core dans Visual Studio.

  1. Lancez l'IDE de Visual Studio.
  2. Cliquez sur "Créer un nouveau projet".
  3. Dans la fenêtre «Créer un nouveau projet», sélectionnez «Application Web ASP.NET Core» dans la liste des modèles affichés.
  4. Cliquez sur Suivant.
  5. Dans la fenêtre «Configurer votre nouveau projet» ci-dessous, spécifiez le nom et l'emplacement du nouveau projet.
  6. Cliquez sur Créer.
  7. Dans la fenêtre «Créer une nouvelle application Web ASP.NET Core», sélectionnez .NET Core comme moteur d'exécution et ASP.NET Core 2.2 (ou version ultérieure) dans la liste déroulante en haut. J'utiliserai ASP.NET Core 3.0 ici.
  8. Sélectionnez «API» comme modèle de projet pour créer une nouvelle application API ASP.NET Core. 
  9. Assurez-vous que les cases à cocher «Activer le support Docker» et «Configurer pour HTTPS» ne sont pas cochées car nous n'utiliserons pas ces fonctionnalités ici.
  10. Assurez-vous que l'authentification est définie sur «Aucune authentification» car nous n'utiliserons pas non plus l'authentification.
  11. Cliquez sur Créer. 

Cela créera un nouveau projet d'API ASP.NET Core dans Visual Studio. Sélectionnez le dossier de solution Contrôleurs dans la fenêtre Explorateur de solutions et cliquez sur «Ajouter -> Contrôleur…» pour créer un nouveau contrôleur nommé DefaultController.

Ensuite, pour travailler avec Quartz, vous devez installer le package Quartz de NuGet. Vous pouvez le faire via le gestionnaire de packages NuGet dans l'IDE de Visual Studio 2019 ou en exécutant la commande suivante sur la console du gestionnaire de packages NuGet:

Quartz du package d'installation

Tâches, déclencheurs et planificateurs Quartz.NET 

Les trois principaux concepts de Quartz.NET sont les tâches, les déclencheurs et les planificateurs. Un travail contient le code pour exécuter une tâche ou un travail à effectuer. Un travail est représenté par une classe qui implémente l'interface IJob. Un déclencheur est utilisé pour spécifier la planification et d'autres détails d'un travail. Vous pouvez profiter d'un déclencheur pour spécifier la manière dont le travail doit être exécuté. Le planificateur est le composant responsable de l'interrogation et de l'exécution des travaux en fonction de plannings prédéfinis.

Créer un planificateur à l'aide de Quartz.NET

Il est à noter que vous pouvez avoir plusieurs planificateurs dans une application. Cependant, nous n'utiliserons qu'un seul planificateur ici pour des raisons de simplicité. L'extrait de code suivant illustre comment vous pouvez créer une instance de planificateur.

var scheduler = StdSchedulerFactory.GetDefaultScheduler (). GetAwaiter (). GetResult ();

Une fois le planificateur créé, vous pouvez utiliser le code suivant dans la méthode ConfigureServices du fichier Startup.cs pour ajouter l'instance du planificateur en tant que service singleton.

services.AddSingleton (planificateur);

Démarrer et arrêter un planificateur à l'aide de Quartz.NET

Pour démarrer et arrêter le planificateur, nous profiterons d'un service d'hébergement. Pour ce faire, vous devez créer une classe qui implémente l'interface IHostingService comme indiqué dans l'extrait de code ci-dessous.

classe publique CustomQuartzHostedService: IHostedService

{

        private readonly IScheduler _scheduler;

        public CustomQuartzHostedService (planificateur IScheduler)

        {

            _scheduler = planificateur;

        }

        Tâche publique async StartAsync (CancellationToken cancelToken)

        {

            attendre _scheduler? .Start (annulationToken);

        }

        Public async Task StopAsync (CancellationToken annulationToken)

        {

            attendre _scheduler? .Shutdown (annulationToken);

        }

 }

Notez que vous devez enregistrer le service hébergé dans la collection de services dans la méthode ConfigureServices à l'aide de l'extrait de code ci-dessous.

services.AddHostedService ();

Voici la méthode ConfigureServices mise à jour pour votre référence:

public void ConfigureServices (services IServiceCollection)

{

    services.AddControllers ();

    var scheduler =

    StdSchedulerFactory.GetDefaultScheduler (). GetAwaiter (). GetResult ();

    services.AddSingleton (planificateur);

    services.AddHostedService ();

}

Créer un travail à l'aide de Quartz.NET

Comme je l'ai dit plus tôt, un travail est une classe qui implémente l'interface IJob et contient la méthode Execute (). La méthode Execute () accepte une instance de type IJobExecutionContext.

L'extrait de code suivant illustre une classe de travail qui contient également une méthode Execute () asynchrone. Cette méthode contient le code qui correspond à la tâche que votre travail doit effectuer.

[DisallowConcurrentExecution]

Classe publique NotificationJob: IJob

    {

        privé en lecture seule ILogger _logger;

        NotificationJob public (enregistreur ILogger)

        {

            _logger = enregistreur;

        }

        Exécution de tâche publique (contexte IJobExecutionContext)

        {

            _logger.LogInformation ("Bonjour tout le monde!");

            return Task.CompletedTask;

        }

    }

Créer une fabrique de travaux à l'aide de Quartz.NET

Une fabrique de travaux est une classe qui hérite de l'interface IJobFactory et implémente les méthodes NewJob () et ReturnJob (). L'extrait de code suivant peut être utilisé pour créer une classe de fabrique qui peut créer et renvoyer une instance de travail.

classe publique CustomQuartzJobFactory: IJobFactory

    {

        private readonly IServiceProvider _serviceProvider;

        public CustomQuartzJobFactory (IServiceProvider serviceProvider)

        {

            _serviceProvider = serviceProvider;

        }

        public IJob NewJob (TriggerFiredBundle triggerFiredBundle,

        Planificateur IScheduler)

        {

            var jobDetail = triggerFiredBundle.JobDetail;

            return (IJob) _serviceProvider.GetService (jobDetail.JobType);

        }

        public void ReturnJob (travail IJob) {}

    }

Notez que cette implémentation ne tire pas parti du regroupement de tâches. Si vous souhaitez utiliser le regroupement de tâches, vous devez modifier la méthode NewJob (), puis implémenter la méthode ReturnJob ().

Créez une classe JobMetadata pour stocker vos métadonnées de travail

Nous utiliserons une classe personnalisée pour stocker les métadonnées liées à un travail, c'est-à-dire l'ID du travail, son nom, etc. La classe suivante représente la classe de métadonnées du travail.

classe publique JobMetadata

    {

        public Guid JobId {get; ensemble; }

        public Type JobType {get; }

        chaîne publique JobName {get; }

        chaîne publique CronExpression {get; }

        public JobMetadata (ID Guid, type jobType, chaîne jobName,

        string cronExpression)

        {

            JobId = Id;

            JobType = type de travail;

            JobName = jobName;

            CronExpression = cronExpression;

        }

    }

Créez un service hébergé pour démarrer et arrêter le planificateur Quartz.NET

Ensuite, nous devrons implémenter un service hébergé. Un service hébergé est une classe qui implémente l'interface IHostedService et démarre le planificateur Quartz. La liste de code suivante illustre une classe de service hébergé personnalisée.

classe publique CustomQuartzHostedService: IHostedService

    {

        private readonly ISchedulerFactory schedulerFactory;

        privé en lecture seule IJobFactory jobFactory;

        privé en lecture seule JobMetadata jobMetadata;

        public CustomQuartzHostedService (ISchedulerFactory

            schedulerFactory,

            JobMetadata jobMetadata,

            IJobFactory jobFactory)

        {

            this.schedulerFactory = schedulerFactory;

            this.jobMetadata = jobMetadata;

            this.jobFactory = jobFactory;

        }

        public IScheduler Scheduler {get; ensemble; }

        Tâche publique async StartAsync (CancellationToken cancelToken)

        {

            Scheduler = attendre schedulerFactory.GetScheduler ();

            Scheduler.JobFactory = jobFactory;

            var job = CreateJob (jobMetadata);

            var trigger = CreateTrigger (jobMetadata);

            attendre Scheduler.ScheduleJob (travail, déclencheur, annulationToken);

            attendre Scheduler.Start (annulationToken);

        }

        Public async Task StopAsync (CancellationToken annulationToken)

        {

            attendre Scheduler? .Shutdown (annulationToken);

        }

        ITrigger privé CreateTrigger (JobMetadata jobMetadata)

        {

            retourne TriggerBuilder.Create ()

            .WithIdentity (jobMetadata.JobId.ToString ())

            .WithCronSchedule (jobMetadata.CronExpression)

            .WithDescription ($ "{jobMetadata.JobName}")

            .Construire();

        }

        private IJobDetail CreateJob (JobMetadata jobMetadata)

        {

            retourner JobBuilder

            .Create (jobMetadata.JobType)

            .WithIdentity (jobMetadata.JobId.ToString ())

            .WithDescription ($ "{jobMetadata.JobName}")

            .Construire();

        }

    }

L'extrait de code suivant montre le code complet de la méthode ConfigureServices de la classe Startup.

public void ConfigureServices (services IServiceCollection)

{

services.AddControllers ();

services.AddSingleton ();

services.AddSingleton ();

services.AddSingleton ();

services.AddSingleton (new JobMetadata (Guid.NewGuid (), typeof (NotificationJob), "Notification Job", "0/10 * * * *?"));

services.AddHostedService ();

}

Et c'est tout ce que vous avez à faire! Lorsque vous exécutez l'application, vous observerez que la méthode Execute () de la classe NotificationJob s'exécute une fois toutes les 10 secondes.

Quartz.NET est un bon choix pour implémenter des planificateurs dans vos applications. Vous pouvez également profiter de la fonctionnalité de persistance de Quartz.NET pour stocker vos travaux dans une base de données telle que SQL Server, PostgreSQL ou SQLite.