C job scheduling Quartz.NET Learning notes

Keywords: C# Database github Windows

I. brief introduction

    Quartz.NET It is a powerful, open source and lightweight job scheduling framework. It is a. Net porting of OpenSymphony's Quartz API. It can be rewritten with C ා and can be used in WinForm and WinForm ASP.NET In use. It is flexible and uncomplicated, and can create simple or complex job scheduling for executing a job. It has many features, such as database support, clustering, plug-ins, support for cron like expressions and so on.

Official website: http://www.quartz-scheduler.net/

Source code: https://github.com/quartznet/quartznet

Example: http://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html

II. Concept interpretation

Scheduler: job scheduler.

IJob: job interface, inherit and implement Execute, and write specific job logic for execution.

JobBuilder: generate a detailed job information (JobDetail) according to the settings.

Trigger Builder: according to the rules, the corresponding trigger is produced.

III. example program

3.1 interface

Create a WinForm program Client, right-click the project - > properties - > Application - > output type, and select console application.

3.2 reference

Right click Project - > manage NuGet packages - > Quartz.NET .

3.2 operation

Create a new class DataSyncJob and inherit IJob, which means it is a job and implements Execute method.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Quartz;

namespace LinkTo.Test.Quartz.Client
{
    //start to fight DisallowConcurrentExecution Label let Job Carry out single track run to avoid repeated execution when not finished.
    [DisallowConcurrentExecution]
    public class DataSyncJob : IJob
    {
        public Task Execute(IJobExecutionContext context)
        {
            JobDataMap keyValuePairs = context.MergedJobDataMap;
            if (keyValuePairs.Count > 0 && keyValuePairs.Contains("Hello"))
            {
                string value = context.MergedJobDataMap.Get("Hello").ToString();
                return Task.Run(() =>
                {
                    Console.WriteLine(DateTime.Now + $" Hello: {value}" + Environment.NewLine);
                });
            }
            else
            {
                return Task.Run(() =>
                {
                    Console.WriteLine(DateTime.Now + Environment.NewLine);
                });
            }
        }
    }
}

Description:

1) generally speaking, jobs need to be labeled with [disallowcurrentexecution] to avoid being scheduled when the job is not completed.

2) the job can receive the parameter (key value) passed by the trigger. The above job receives the "Hello" parameter.

3.3 dispatch

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Quartz;
using Quartz.Impl;

namespace LinkTo.Test.Quartz.Client
{
    public partial class Main : Form
    {
        //Dispatcher factory
        private ISchedulerFactory factory;
        //Scheduler
        private IScheduler scheduler;

        public Main()
        {
            InitializeComponent();
            //Button status
            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }

        /// <summary>
        /// start
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btnStart_Click(object sender, EventArgs e)
        {
            //1,Create a scheduler
            factory = new StdSchedulerFactory();
            scheduler = await factory.GetScheduler();
            await scheduler.Start();

            //2,Create a task
            IJobDetail job = JobBuilder.Create<DataSyncJob>().WithIdentity("DataSync", "DataSync_Group").Build();

            //3,Create a trigger(There are four triggers to choose from)
            //4,Add tasks and triggers to the scheduler

            #region Trigger 1: WithSimpleSchedule
            //ITrigger simpleTrigger = TriggerBuilder.Create()
            //    .WithIdentity("DataSync_SimpleTrigger", "DataSync_TriggerGroup")
            //    .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever())
            //    .Build();
            //await scheduler.ScheduleJob(job, simpleTrigger);
            #endregion

            #region Trigger 2: WithDailyTimeIntervalSchedule
            //ITrigger dailyTimeTrigger = TriggerBuilder.Create()
            //    .WithIdentity("DataSync_DailyTimeTrigger", "DataSync_TriggerGroup")
            //    .WithDailyTimeIntervalSchedule(x => x.OnEveryDay().WithIntervalInSeconds(5))
            //    .Build();
            //await scheduler.ScheduleJob(job, dailyTimeTrigger);
            #endregion

            #region Trigger 3: WithCalendarIntervalSchedule
            //ITrigger calendarTrigger = TriggerBuilder.Create()
            //    .WithIdentity("DataSync_CalendarTrigger", "DataSync_TriggerGroup")
            //    .WithCalendarIntervalSchedule(x => x.WithIntervalInSeconds(5))
            //    .Build();
            //await scheduler.ScheduleJob(job, calendarTrigger);
            #endregion

            #region Trigger 4: WithCronSchedule(With pass through parameters"Hello")
            ITrigger cronTrigger = TriggerBuilder.Create()
                .WithIdentity("DataSync_CronTrigger", "DataSync_TriggerGroup")
                .WithCronSchedule("0/5 * * * * ?")
                .UsingJobData("Hello", Guid.NewGuid().ToString())
                .Build();
            await scheduler.ScheduleJob(job, cronTrigger);
            #endregion

            //5,Start execution
            await scheduler.Start();

            //Button status
            btnStart.Enabled = false;
            btnStop.Enabled = true;
        }

        /// <summary>
        /// stop it
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            if (scheduler != null)
            {
                scheduler.Shutdown(true);
            }
            //Button status
            btnStart.Enabled = true;
            btnStop.Enabled = false;
        }
    }
}

Description:

1) both Job and Trigger use * * Group when they are with identity. Here, Group is used for classification, which is equivalent to a namespace.

2) there are four types of triggers, namely, WithSimpleSchedule, WithDailyTimeIntervalSchedule, WithCalendarIntervalSchedule and WithCronSchedule. The first and fourth types are commonly used.

3) Cron expression is used for WithCronSchedule trigger.

3.4 results

4. Cron expression

1) online Cron expression generator: https://cron.qqe2.com/

2) official English Introduction: https://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/crontrigger.html

3) Cron expressions are easy to understand as a whole, and only one thing needs to be noted is the usage of the "?" sign. "?" can be used in Day of Month and Day of Week, for example, the 31st minute of every hour on the 1st of every month. The correct expression is: * 31 * 1 *? ", but not: * 31 * 1 * *, because this represents any day of every week.

Cron expression consists of 7 segments: second minute day month week year (optional)

"-": refers to the range, MON-WED refers to Monday to Wednesday.
",": for enumeration, MON,WEB for Monday and Wednesday.
"*": means "every", day, month, week, year, etc.
"/": indicates increment, 0 / 15 (minute) indicates every 15 minutes, starting after 0 minute; 3 / 20 indicates every 20 minutes, starting after 3 minutes.
"?": it can only appear in the day and week segments, indicating that no specific value is specified.
"L": it can only appear in days and weeks. It is the abbreviation of Last, which means the Last day of a month and the Last day of a week (Saturday).
"W": indicates the working day, which is the closest to the given value.
"ා" means the week ordinal of a month, "6 × 3" means the third Friday of each month (1=SUN...6=FRI,7=SAT).

4) official example:

expression explain
0 0 12 * * ? Triggered at 12 noon every day
0 15 10 ? * * Triggered at 10:15 a.m. every day
0 15 10 * * ? Triggered at 10:15 a.m. every day
0 15 10 * * ? * Triggered at 10:15 a.m. every day
0 15 10 * * ? 2005 Triggered at 10:15 a.m. every day in 2005
0 * 14 * * ? Triggered every 1 minute from 2pm to 2pm every day
0 0/5 14 * * ? Triggered every 5 minutes between 2:00 p.m. and 2:55 p.m. every day
0 0/5 14,18 * * ? Triggered every 5 minutes between 2:00 p.m. and 2:55 p.m. and between 6:00 p.m. and 6:55 p.m. every day
0 0-5 14 * * ? Triggered every 1 minute from 2pm to 2pm every day
0 10,44 14 ? 3 WED Triggered every March at 2:10 and 2:44 p.m
0 15 10 ? * MON-FRI 10:15 am from Monday to Friday
0 15 10 15 * ? Triggered at 10:15 am on the 15th day of each month
0 15 10 L * ? Triggered at 10:15 am on the last day of each month
0 15 10 L-2 * ? Triggered from the second to the last day of each month at 10:15 a.m
0 15 10 ? * 6L Triggered at 10:15 am on the last Friday of each month
0 15 10 ? * 6L Triggered at 10:15 a.m. on the last Friday of each month
0 15 10 ? * 6L 2002-2005 Triggered at 10:15 a.m. on the last Friday of each month from 2002 to 2005
0 15 10 ? * 6#3 Triggered at 10:15 am on the third Friday of each month
0 0 12 1/5 * ? Triggered every 5 days of the month at 12:00 p.m. (noon), starting from the first day of the month
0 11 11 11 11 ? Triggered every 11:11 a.m. on November 11

V. one line code scheduling

Create a new TestJob:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Quartz;

namespace LinkTo.Test.Quartz.Client
{
    //start to fight DisallowConcurrentExecution Label let Job Carry out single track run to avoid repeated execution when not finished.
    [DisallowConcurrentExecution]
    public class TestJob : IJob
    {
        public Task Execute(IJobExecutionContext context)
        {
            return Task.Run(() =>
            {
                Console.WriteLine(DateTime.Now + Environment.NewLine);
            });
        }
    }
}
TestJob.cs

Create a new scheduling encapsulation class, QuartzFactory:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;

namespace LinkTo.Test.Quartz.Client
{
    public class QuartzFactory
    {
        //Dispatcher factory
        private static ISchedulerFactory factory = null;
        //Scheduler
        private static IScheduler scheduler = null;

        /// <summary>
        /// Constructor
        /// </summary>
        static QuartzFactory()
        {
            factory = new StdSchedulerFactory();
            scheduler = factory.GetScheduler().Result;
            scheduler.Start();
        }

        #region Trigger 1: add Job
        /// <summary>
        /// Trigger 1: add Job And operate in the form of cycle
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobName"></param>
        /// <param name="startTime"></param>
        /// <param name="simpleTime"></param>
        /// <param name="jobDataMap"></param>
        /// <returns></returns>
        public static DateTimeOffset AddJob<T>(string jobName, DateTimeOffset startTime, TimeSpan simpleTime, Dictionary<string, object> jobDataMap) where T : IJob
        {
            IJobDetail jobCheck = JobBuilder.Create<T>().WithIdentity(jobName, jobName + "_Group").Build();
            jobCheck.JobDataMap.PutAll(jobDataMap);
            ISimpleTrigger triggerCheck = new SimpleTriggerImpl(jobName + "_SimpleTrigger", 
                jobName + "_TriggerGroup",
                startTime,
                null,
                SimpleTriggerImpl.RepeatIndefinitely,
                simpleTime);
            return scheduler.ScheduleJob(jobCheck, triggerCheck).Result;
        }

        /// <summary>
        /// Trigger 1: add Job And operate in the form of cycle
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobName"></param>
        /// <param name="startTime"></param>
        /// <param name="simpleTime">Msec </param>
        /// <param name="mapKey"></param>
        /// <param name="mapValue"></param>
        /// <returns></returns>
        public static DateTimeOffset AddJob<T>(string jobName, DateTimeOffset startTime, int simpleTime, string mapKey, object mapValue) where T : IJob
        {
            Dictionary<string, object> jobDataMap = new Dictionary<string, object>
            {
                { mapKey, mapValue }
            };
            return AddJob<T>(jobName, startTime, TimeSpan.FromMilliseconds(simpleTime), jobDataMap);
        }

        /// <summary>
        /// Trigger 1: add Job And operate in the form of cycle
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobName"></param>
        /// <param name="startTime"></param>
        /// <param name="simpleTime"></param>
        /// <returns></returns>
        public static DateTimeOffset AddJob<T>(string jobName, DateTimeOffset startTime, TimeSpan simpleTime) where T : IJob
        {
            return AddJob<T>(jobName, startTime, simpleTime, new Dictionary<string, object>());
        }

        /// <summary>
        /// Trigger 1: add Job And operate in the form of cycle
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobName"></param>
        /// <param name="startTime"></param>
        /// <param name="simpleTime">Msec </param>
        /// <returns></returns>
        public static DateTimeOffset AddJob<T>(string jobName, DateTimeOffset startTime, int simpleTime) where T : IJob
        {
            return AddJob<T>(jobName, startTime, TimeSpan.FromMilliseconds(simpleTime));
        }

        /// <summary>
        /// Trigger 1: add Job And operate in the form of cycle
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobName"></param>
        /// <param name="simpleTime">Msec </param>
        /// <returns></returns>
        public static DateTimeOffset AddJob<T>(string jobName, int simpleTime) where T : IJob
        {
            return AddJob<T>(jobName, DateTime.UtcNow.AddMilliseconds(1), TimeSpan.FromMilliseconds(simpleTime));
        }
        #endregion

        #region Trigger 4: add Job
        /// <summary>
        /// Trigger 4: add Job And run as a fixed point
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobName"></param>
        /// <param name="cronTime"></param>
        /// <param name="jobDataMap"></param>
        /// <returns></returns>
        public static DateTimeOffset AddJob<T>(string jobName, string cronTime, string jobData) where T : IJob
        {
            IJobDetail jobCheck = JobBuilder.Create<T>().WithIdentity(jobName, jobName + "_Group").UsingJobData("jobData", jobData).Build();
            ICronTrigger cronTrigger = new CronTriggerImpl(jobName + "_CronTrigger", jobName + "_TriggerGroup", cronTime);
            return scheduler.ScheduleJob(jobCheck, cronTrigger).Result;
        }

        /// <summary>
        /// Trigger 4: add Job And run as a fixed point
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jobName"></param>
        /// <param name="cronTime"></param>
        /// <returns></returns>
        public static DateTimeOffset AddJob<T>(string jobName, string cronTime) where T : IJob
        {
            return AddJob<T>(jobName, cronTime, null);
        }
        #endregion

        /// <summary>
        /// Modify trigger time overload
        /// </summary>
        /// <param name="jobName">Job name</param>
        /// <param name="timeSpan">TimeSpan</param>
        /// </summary>
        public static void UpdateTime(string jobName, TimeSpan simpleTimeSpan)
        {
            TriggerKey triggerKey = new TriggerKey(jobName + "_SimpleTrigger", jobName + "_TriggerGroup");
            SimpleTriggerImpl simpleTriggerImpl = scheduler.GetTrigger(triggerKey).Result as SimpleTriggerImpl;
            simpleTriggerImpl.RepeatInterval = simpleTimeSpan;
            scheduler.RescheduleJob(triggerKey, simpleTriggerImpl);
        }

        /// <summary>
        /// Modify trigger time overload
        /// </summary>
        /// <param name="jobName">Job name</param>
        /// <param name="simpleTime">Minutes</param>
        /// <summary>
        public static void UpdateTime(string jobName, int simpleTime)
        {
            UpdateTime(jobName, TimeSpan.FromMinutes(simpleTime));
        }

        /// <summary>
        /// Modify trigger time overload
        /// </summary>
        /// <param name="jobName">Job name</param>
        /// <param name="cronTime">Cron expression</param>
        public static void UpdateTime(string jobName, string cronTime)
        {
            TriggerKey triggerKey = new TriggerKey(jobName + "_CronTrigger", jobName + "_TriggerGroup");
            CronTriggerImpl cronTriggerImpl = scheduler.GetTrigger(triggerKey).Result as CronTriggerImpl;
            cronTriggerImpl.CronExpression = new CronExpression(cronTime);
            scheduler.RescheduleJob(triggerKey, cronTriggerImpl);
        }

        /// <summary>
        /// Pause all Job
        /// </summary>
        public static void PauseAll()
        {
            scheduler.PauseAll();
        }

        /// <summary>
        /// Restore all Job
        /// </summary>
        public static void ResumeAll()
        {
            scheduler.ResumeAll();
        }

        /// <summary>
        /// Delete assignments Job
        /// </summary>
        /// <param name="jobName"></param>
        public static void DeleteJob(string jobName)
        {
            JobKey jobKey = new JobKey(jobName, jobName + "_Group");
            scheduler.DeleteJob(jobKey);
        }

        /// <summary>
        /// Unload timer
        /// </summary>
        /// <param name="isWaitForToComplete">Wait or not Job Execution complete</param>
        public static void Shutdown(bool isWaitForToComplete)
        {
            scheduler.Shutdown(isWaitForToComplete);
        }
    }
}
QuartzFactory.cs

One line of code realizes job scheduling button code:

        /// <summary>
        /// One line of code for job scheduling
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOneCode_Click(object sender, EventArgs e)
        {
            if (btnOneCode.Text == "One line of code for job scheduling")
            {
                string cronTime = "0/5 * * * * ?";
                QuartzFactory.AddJob<TestJob>("TestJob", cronTime);
                btnOneCode.Text = "Stop";
            }
            else
            {
                QuartzFactory.DeleteJob("TestJob");
                btnOneCode.Text = "One line of code for job scheduling";
            }
        }
btnOneCode_Click

 

Reference from:

    https://www.cnblogs.com/best/p/7658573.html

Posted by ducky on Wed, 20 May 2020 03:17:19 -0700