Comment configurer des taches planifiées avec quartz en C#

Dans cet article nous allons voir comment mettre en place des taches planifiées avec quartz en C#.

Quartz.net est une librairie open source qui permet de planifier des tâches en (.NET). Il peut être intégré dans n’importe quelle application.

Quartz peut être utilisé pour créer des programmes complexes qui réalisent des traitements lourds et qui consomment beaucoup de ressources du serveur.

1)      Installation Quartz avec Nuget Package

Lancez Visual Studio, cliquez droit sur les références de votre projet et choisissez (Manage Nuget Packages..).
Choisissez Quartz.NET dans les résultats de recherche et cliquez sur installer.

2)      Configuration

Pour configurer votre projet quartz, vous pouvez utiliser le fichier de config (quartz.config) situé à la racine de votre application.

<quartz>
    <add key="quartz.scheduler.instanceName" value="TestScheduler" />
    <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
    <add key="quartz.threadPool.threadCount" value="2" />
    <add key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />

</quartz>

-    quartz.scheduler.instanceName : Le nom de l’ordonnanceur sera TestScheduler.

-    quartz.threadPool.threadCount : Il y a 2 threads dans le pool .Ce qui signifie qu’un maximum de deux jobs peut être exécuté simultanément.

3)      Premier exemple

Après installation et configuration du projet quartz, on commence notre premier exemple :

using System;
using System.Threading;

using Quartz;
using Quartz.Impl;
using Quartz.Job;

namespace TestApplication1
{
    public class Program
    {
        private static void Main(string[] args)
        {
            try
            {

                IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();

                scheduler.Start();

                // définir le job et l’attacher à notre classe TestJob
                IJobDetail job = JobBuilder.Create<TestJob>()
                    .WithIdentity("testJob", "TestApplication")
                    .Build();

                // Déclencher la tache à executer , puis la répéter toutes les 10 secendes  
                ITrigger trigger = TriggerBuilder.Create()
                    .WithIdentity("testTrigger", " TestApplication")
                    .StartNow()
                    .WithSimpleSchedule(x => x
                        .WithIntervalInSeconds(10)
                        .RepeatForever())
                    .Build();

                scheduler.ScheduleJob(job, trigger);

                scheduler.Shutdown();
            }
            catch (SchedulerException se)
            {
                Console.WriteLine(se);
            }

            Console.WriteLine("Press any key to close the application");
            Console.ReadKey();
        }
    }

    public class TestJob : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            Console.WriteLine("Greetings from TestJob!");
        }
    }
} 

4)      Configurer Quartz.Net en utilisant SQL et Asp.net

Base de données

Nous devons d’abord mettre en place la base de données SQL. Quart.Net persisteront tous les détails des jobs et des triggers à cette base de données.

La meilleure façon de créer les tables requises par quartz est d’exécuter ce script SQL.

CREATE TABLE [QRTZ_CALENDARS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [CALENDAR_NAME] [NVARCHAR] (200)  NOT NULL ,
  [CALENDAR] [IMAGE] NOT NULL
) 
GO

CREATE TABLE [QRTZ_CRON_TRIGGERS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [TRIGGER_NAME] [NVARCHAR] (150)  NOT NULL ,
  [TRIGGER_GROUP] [NVARCHAR] (150)  NOT NULL ,
  [CRON_EXPRESSION] [NVARCHAR] (120)  NOT NULL ,
  [TIME_ZONE_ID] [NVARCHAR] (80) 
)
GO

CREATE TABLE [QRTZ_FIRED_TRIGGERS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [ENTRY_ID] [NVARCHAR] (95)  NOT NULL ,
  [TRIGGER_NAME] [NVARCHAR] (150)  NOT NULL ,
  [TRIGGER_GROUP] [NVARCHAR] (150)  NOT NULL ,
  [INSTANCE_NAME] [NVARCHAR] (200)  NOT NULL ,
  [FIRED_TIME] [BIGINT] NOT NULL ,
  [SCHED_TIME] [BIGINT] NOT NULL ,
  [PRIORITY] [INTEGER] NOT NULL ,
  [STATE] [NVARCHAR] (16)  NOT NULL,
  [JOB_NAME] [NVARCHAR] (150)  NULL ,
  [JOB_GROUP] [NVARCHAR] (150)  NULL ,
  [IS_NONCONCURRENT] BIT  NULL ,
  [REQUESTS_RECOVERY] BIT  NULL 
)
GO

CREATE TABLE [QRTZ_PAUSED_TRIGGER_GRPS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [TRIGGER_GROUP] [NVARCHAR] (150)  NOT NULL 
)
GO

CREATE TABLE [QRTZ_SCHEDULER_STATE] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [INSTANCE_NAME] [NVARCHAR] (200)  NOT NULL ,
  [LAST_CHECKIN_TIME] [BIGINT] NOT NULL ,
  [CHECKIN_INTERVAL] [BIGINT] NOT NULL
)
GO

CREATE TABLE [QRTZ_LOCKS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [LOCK_NAME] [NVARCHAR] (40)  NOT NULL 
)
GO

CREATE TABLE [QRTZ_JOB_DETAILS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [JOB_NAME] [NVARCHAR] (150)  NOT NULL ,
  [JOB_GROUP] [NVARCHAR] (150)  NOT NULL ,
  [DESCRIPTION] [NVARCHAR] (250) NULL ,
  [JOB_CLASS_NAME] [NVARCHAR] (250)  NOT NULL ,
  [IS_DURABLE] BIT  NOT NULL ,
  [IS_NONCONCURRENT] BIT  NOT NULL ,
  [IS_UPDATE_DATA] BIT  NOT NULL ,
  [REQUESTS_RECOVERY] BIT  NOT NULL ,
  [JOB_DATA] [IMAGE] NULL
)
GO

CREATE TABLE [QRTZ_SIMPLE_TRIGGERS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [TRIGGER_NAME] [NVARCHAR] (150)  NOT NULL ,
  [TRIGGER_GROUP] [NVARCHAR] (150)  NOT NULL ,
  [REPEAT_COUNT] [INTEGER] NOT NULL ,
  [REPEAT_INTERVAL] [BIGINT] NOT NULL ,
  [TIMES_TRIGGERED] [INTEGER] NOT NULL
)
GO

CREATE TABLE [QRTZ_SIMPROP_TRIGGERS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [TRIGGER_NAME] [NVARCHAR] (150)  NOT NULL ,
  [TRIGGER_GROUP] [NVARCHAR] (150)  NOT NULL ,
  [STR_PROP_1] [NVARCHAR] (512) NULL,
  [STR_PROP_2] [NVARCHAR] (512) NULL,
  [STR_PROP_3] [NVARCHAR] (512) NULL,
  [INT_PROP_1] [INT] NULL,
  [INT_PROP_2] [INT] NULL,
  [LONG_PROP_1] [BIGINT] NULL,
  [LONG_PROP_2] [BIGINT] NULL,
  [DEC_PROP_1] [NUMERIC] (13,4) NULL,
  [DEC_PROP_2] [NUMERIC] (13,4) NULL,
  [BOOL_PROP_1] BIT NULL,
  [BOOL_PROP_2] BIT NULL
)
GO

CREATE TABLE [QRTZ_BLOB_TRIGGERS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [TRIGGER_NAME] [NVARCHAR] (150)  NOT NULL ,
  [TRIGGER_GROUP] [NVARCHAR] (150)  NOT NULL ,
  [BLOB_DATA] [IMAGE] NULL
)
GO

CREATE TABLE [QRTZ_TRIGGERS] (
  [SCHED_NAME] [NVARCHAR] (100)  NOT NULL ,
  [TRIGGER_NAME] [NVARCHAR] (150)  NOT NULL ,
  [TRIGGER_GROUP] [NVARCHAR] (150)  NOT NULL ,
  [JOB_NAME] [NVARCHAR] (150)  NOT NULL ,
  [JOB_GROUP] [NVARCHAR] (150)  NOT NULL ,
  [DESCRIPTION] [NVARCHAR] (250) NULL ,
  [NEXT_FIRE_TIME] [BIGINT] NULL ,
  [PREV_FIRE_TIME] [BIGINT] NULL ,
  [PRIORITY] [INTEGER] NULL ,
  [TRIGGER_STATE] [NVARCHAR] (16)  NOT NULL ,
  [TRIGGER_TYPE] [NVARCHAR] (8)  NOT NULL ,
  [START_TIME] [BIGINT] NOT NULL ,
  [END_TIME] [BIGINT] NULL ,
  [CALENDAR_NAME] [NVARCHAR] (200)  NULL ,
  [MISFIRE_INSTR] [INTEGER] NULL ,
  [JOB_DATA] [IMAGE] NULL
)
GO

ALTER TABLE [QRTZ_CALENDARS]  ADD
  CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [CALENDAR_NAME]
  ) 
GO

ALTER TABLE [QRTZ_CRON_TRIGGERS] ADD
  CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) 
GO

ALTER TABLE [QRTZ_FIRED_TRIGGERS] ADD
  CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [ENTRY_ID]
  ) 
GO

ALTER TABLE [QRTZ_PAUSED_TRIGGER_GRPS] ADD
  CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [TRIGGER_GROUP]
  ) 
GO

ALTER TABLE [QRTZ_SCHEDULER_STATE] ADD
  CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY 
  (
    [SCHED_NAME],
    [INSTANCE_NAME]
  ) 
GO

ALTER TABLE [QRTZ_LOCKS] ADD
  CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [LOCK_NAME]
  ) 
GO

ALTER TABLE [QRTZ_JOB_DETAILS] ADD
  CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [JOB_NAME],
    [JOB_GROUP]
  ) 
GO

ALTER TABLE [QRTZ_SIMPLE_TRIGGERS] ADD
  CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) 
GO

ALTER TABLE [QRTZ_SIMPROP_TRIGGERS] ADD
  CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) 
GO

ALTER TABLE [QRTZ_TRIGGERS] ADD
  CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY 
  (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) 
GO

ALTER TABLE [QRTZ_CRON_TRIGGERS] ADD
  CONSTRAINT [FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY
  (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) REFERENCES [QRTZ_TRIGGERS] (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) ON DELETE CASCADE
GO

ALTER TABLE [QRTZ_SIMPLE_TRIGGERS] ADD
  CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY
  (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) REFERENCES [QRTZ_TRIGGERS] (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) ON DELETE CASCADE
GO

ALTER TABLE [QRTZ_SIMPROP_TRIGGERS] ADD
  CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY
  (
	[SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) REFERENCES [QRTZ_TRIGGERS] (
    [SCHED_NAME],
    [TRIGGER_NAME],
    [TRIGGER_GROUP]
  ) ON DELETE CASCADE
GO

ALTER TABLE [QRTZ_TRIGGERS] ADD
  CONSTRAINT [FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] FOREIGN KEY
  (
    [SCHED_NAME],
    [JOB_NAME],
    [JOB_GROUP]
  ) REFERENCES [QRTZ_JOB_DETAILS] (
    [SCHED_NAME],
    [JOB_NAME],
    [JOB_GROUP]
  )
GO

CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP)
GO
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP)
GO
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME)
GO
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP)
GO
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE)
GO
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE)
GO
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE)
GO
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME)
GO
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME)
GO
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME)
GO
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE)
GO
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE)
GO
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME)
GO
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY)
GO
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP)
GO
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP)
GO
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
GO
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP)
GO

tableSqljpg

La prochaine étape est de développer une application pour l’exécution des jobs quartz.

Application ASP.NET

Après la mise en place de la base de données quartz, nous avons besoin d’un service pour déclencher les jobs. Dans cette partie nous allons utiliser une application Asp.net pour créer les services.

Voici les étapes nécessaires à la création du service :

1)      Créez un nouveau projet avec le modèle " ASP.NET Empty Web Application".

2)      Utilisez Nuget pour installer le package Quartz

3)      Ajoutez un nouvel élément de type  " Global Application Class"(global.asax).

Modifiez le fichier Global.asax.cs  pour que Quartz démarrera et arrêtera avec l’application.

using System;
using Common.Logging;
using Quartz;
using Quartz.Impl;

namespace TestApp
{
    public class Global : System.Web.HttpApplication
    {
        public static IScheduler Scheduler;

        protected void Application_Start(object sender, EventArgs e)
        {
            ISchedulerFactory sf = new StdSchedulerFactory();
            Scheduler = sf.GetScheduler();

            Scheduler.Start();
        }

        protected void Application_End(object sender, EventArgs e)
        {
            Scheduler.Shutdown();
        }
    } 
}

Enfin modifiez le fichier web.config pour inclure la configuration Quartz.Net :

  <quartz>
    <add key="quartz.scheduler.instanceName" value="TestApp" />
    <add key="quartz.scheduler.instanceId" value="AUTO" />

    <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
    <add key="quartz.threadPool.threadCount" value="2" />
    <add key="quartz.threadPool.threadPriority" value="Normal" />

    <add key="quartz.jobStore.useProperties" value="true" />
    <add key="quartz.jobStore.clustered" value="true" />
    <add key="quartz.jobStore.misfireThreshold" value="60000" />
    <add key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
    <add key="quartz.jobStore.tablePrefix" value="QRTZ_" />

    <add key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" />

    <add key="quartz.jobStore.dataSource" value="myDS" />

    <add key="quartz.dataSource.myDS.connectionString" value=" " />
    <add key="quartz.dataSource.myDS.provider" value="SqlServer-20" />
  </quartz>

Lancement du Job

Pour exécuter un job nous avons besoin d’un déclencheur. Voici un exemple qui va ajouter un déclencheur au job qui va s’exécuter 15 secondes après le clic du bouton.

protected void Button1_Click(object sender, EventArgs e)
        {
            var startTime = DateTimeOffset.Now.AddSeconds(15);

            var job = JobBuilder.Create<TestJob>()
                                .WithIdentity("job1", "group1")
                                .Build();

            var trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1", "group1")
                .StartAt(startTime)
                .Build();

            Global.Scheduler.ScheduleJob(job, trigger);
        }   

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.