• 使用 Quartz.NET 实现作业串行执行


    Ø  前言

    前两天,在公司的一个项目中编写 Windows 服务时,需求是当A服务运行完后,B服务才能运行,B服务运行后,C服务才能运行。因为B服务的数据依赖于A服务生成的数据,而C服务的数据又依赖于B服务。

    在之前的文章中有介绍使用 Topshelf 结合 Quartz.NET 创建 Windows 服务,但是当时还不涉及这样的需求,经过后面看过一些相关博客后,便实现了该功能。另外,这里再写个 Demo 研究了一下。

     

    Ø  假设我们有这样一个需求:

    1.   就上一篇使用 Topshelf 结合 Quartz.NET 创建 Windows 服务而言,当我们更新商品库存后,我们需要发送短信和邮件通知管理员。

    2.   而这两个动作都是两个独立的服务作业,并且它们都相互依赖。

    3.   执行顺序:更新商品库存 -> 发送短信 -> 发送邮件,三者都是前一个服务执行完后,接着执行下个服务,下面是具体实现步骤。

     

    1.   首先,我们定义服务配置文件quartz_jobs.xml

    <!--该作业用于定时更新商品库存-->

    <job>

      <name>UpdateInventoryJob</name>

      <group>JobGroup1</group>

      <description>定时更新商品库存</description>

      <job-type>TopshelfAndQuartz.UpdateInventoryJob,TopshelfAndQuartz</job-type>

      <durable>true</durable>

      <recover>false</recover>

    </job>

    <trigger>

      <cron>

        <name>UpdateInventoryTrigger</name>

        <group>UpdateInventoryTriggerGroup</group>

        <job-name>UpdateInventoryJob</job-name>

        <job-group>JobGroup1</job-group>

        <start-time>2017-12-01T00:00:00+08:00</start-time>

        <cron-expression>0 0/1 * * * ?</cron-expression>

      </cron>

    </trigger>

    <!--该作业用于发送短信-->

    <job>

      <name>SendSMSJob</name>

      <group>JobGroup1</group>

      <description>发送短信作业</description>

      <job-type>TopshelfAndQuartz.SendSMSJob,TopshelfAndQuartz</job-type>

      <durable>true</durable>

      <recover>false</recover>

    </job>

    <trigger>

      <cron>

        <name>SendSMSJobTrigger</name>

        <group>SendSMSJobTriggerGroup</group>

        <job-name>SendSMSJob</job-name>

        <job-group>JobGroup1</job-group>

        <start-time>2027-12-01T00:00:00+08:00</start-time>

        <cron-expression>0 0/1 * * * ?</cron-expression>

      </cron>

    </trigger>

    <!--该作业用于发送邮件-->

    <job>

      <name>SendMailJob</name>

      <group>JobGroup1</group>

      <description>发送邮件作业</description>

      <job-type>TopshelfAndQuartz.SendMailJob,TopshelfAndQuartz</job-type>

      <durable>true</durable>

      <recover>false</recover>

    </job>

    <trigger>

      <cron>

        <name>SendMailJobTrigger</name>

        <group>SendMailJobTriggerGroup</group>

        <job-name>SendMailJob</job-name>

        <job-group>JobGroup1</job-group>

        <start-time>2027-12-01T00:00:00+08:00</start-time>

        <cron-expression>0 0/1 * * * ?</cron-expression>

      </cron>

    </trigger>

    1)   可以发现,这里将作业分组名称都命名为“JobGroup1”,这是为了将这三个作业加入作业链中,需要将它们分为同一组中。

    2)   另外,为了防止 SendSMSJobSendMailJob 在服务启动后自动执行,将<start-time>节点设置成了2027-12-01T00:00:00+08:00,因为不希望它们自动执行。

     

    2.   定义发送短信、发送邮件作业(这里只是简单打印执行日志)

    /// <summary>

    /// 发送短信作业。

    /// </summary>

    public class SendSMSJob : IJob

    {

        /// <summary>

        /// 作业被触发时执行该方法。

        /// </summary>

        public void Execute(IJobExecutionContext context)

        {

            Log.Logger.Info("开始执行发送短信作业");

        }

    }

     

    /// <summary>

    /// 发送邮件作业。

    /// </summary>

    public class SendMailJob : IJob

    {

        /// <summary>

        /// 作业被触发时执行该方法。

        /// </summary>

        public void Execute(IJobExecutionContext context)

        {

            Log.Logger.Info("开始执行发送邮件作业");

        }

    }

     

    3.   配置作业监听程序

    /// <summary>

    /// 配置作业监听。

    /// </summary>

    public static void ConfigureJobListener()

    {

        ISchedulerFactory factory = new StdSchedulerFactory();

        IScheduler scheduler = factory.GetScheduler();

        JobChainingJobListener listener = null;

     

        //创建作业Key(名称与分组)

        JobKey uiJobKey = JobKey.Create("UpdateInventoryJob", "JobGroup1");

        JobKey sendSmsJobKey = JobKey.Create("SendSMSJob", "JobGroup1");

        JobKey sendMailJobKey = JobKey.Create("SendMailJob", "JobGroup1");

     

        //设置作业监听链

        listener = new JobChainingJobListener("链接更新库存、发送短信、发送邮件作业");

        listener.AddJobChainLink(uiJobKey, sendSmsJobKey);

        listener.AddJobChainLink(sendSmsJobKey, sendMailJobKey);

        scheduler.ListenerManager.AddJobListener(listener,

            GroupMatcher<JobKey>.GroupEquals("JobGroup1"));

    }

     

    4.   在服务运行前加入作业监听

    Log.Logger.Info("服务开始运行");

    ConfigureJobListener(); //配置作业监听

    HostFactory.Run(o =>

    {

        //o.UseLog4Net(); //这里需要使用 log4net, Version=1.2.15.0 的版本,当前版本不兼容所以注释掉

        o.Service<ServiceRunner>();

        o.SetServiceName("TopshelfAndQuartzService");

        o.SetDisplayName("库存更新服务");

        o.SetDescription("该服务用于定时更新商品库存");

        o.EnablePauseAndContinue();

    });

     

    5.   这样,我们作业监听链就配置好了,运行效果:

    clip_image001[6]

     

    Ø  总结

    1.   其实 Quartz.NET 的功能还是很强大,它支持多个作业或触发设置监听,并可以自定义作业监听(实现 IJobListener 接口)或触发器监听(实现 ITriggerListener 接口),有兴趣的朋友可以深入研究。

    2.   可参考文章:

    1)   https://www.cnblogs.com/linzhao126/p/4528519.html

    2)   http://www.cnblogs.com/zhangzhi19861216/p/4756610.html

    3)   https://www.quartz-scheduler.net/documentation/index.html

  • 相关阅读:
    念大学有用么摘抄
    天行健,君子以自强不息;地势坤,君子以厚德载物。
    加快播放视频的播放速度
    微信语音通话中无法播放聊天对话框中的视频
    劝学
    在这个世界上就是物竞天择,适者生存。弱肉强食,优胜劣汰?
    英语名言名句集锦
    贵州理科状元邹基伟:不放过上课的每一秒
    带宽的理解
    第二章 Python运行程序
  • 原文地址:https://www.cnblogs.com/abeam/p/8661274.html
Copyright © 2020-2023  润新知