(精华)2020年8月14日 C#基础知识点 QuartZ任务调度的使用

(精华)2020年8月14日 C#基础知识点 QuartZ任务调度的使用

第一部分:基础的使用

  1. Nuget引入程序包 QuartZ1. 三大核心对象 IScheduler:时间轴 单元 盒子 在这里进行任务配置 IJobDetail:描述具体做什么事情,定时任务执行的动作 context.MergedJobDataMap 会去掉重复 以后者为准 获取参数严格区分大小写 链式传参: ## 基础代码如下

1:执行代码

#region Scheduler
StdSchedulerFactory factory = new StdSchedulerFactory();
IScheduler scheduler = await factory.GetScheduler();
await scheduler.Start();
#endregion
#region JobDetail
IJobDetail jobDetail = JobBuilder.Create<SendMessage>()//SendMessage是个类
      .WithIdentity("sendJob", "group1")
      .WithDescription("This is sendJob")
      .Build();
jobDetail.JobDataMap.Add("Student1", "参数一");
jobDetail.JobDataMap.Add("Student2", "参数二");
jobDetail.JobDataMap.Add("Student3", "参数三");
jobDetail.JobDataMap.Add("Student4", "参数四");
jobDetail.JobDataMap.Add("Year", DateTime.Now.Year);
#endregion
#region trigger
ITrigger trigger = TriggerBuilder.Create()
       .WithIdentity("sendTrigger", "group1")
       .StartNow()
       .WithCronSchedule("* * * * * ?")//cron表达式
       .WithDescription("This is sendJob's sendTrigger")
       .Build();
trigger.JobDataMap.Add("Student5", "时间参数5");
trigger.JobDataMap.Add("Student6", "时间参数6");
trigger.JobDataMap.Add("Student7", "时间参数7");
trigger.JobDataMap.Add("Student8", "时间参数8");
trigger.JobDataMap.Add("Year", DateTime.Now.Year + 1);
#endregion 

await scheduler.ScheduleJob(jobDetail, trigger);//加入任务和时间策略

2:任务代码

[PersistJobDataAfterExecution] //执行后可以保留执行结果
    [DisallowConcurrentExecution] // 保证不去重复执行   可以把任务串行起来  让一个任务执行完毕以后  才去执行下一个任务
    public class SendMessage : IJob//必须继承IJob
    {<!-- -->

        //private static object obj = new object(); //定义一个静态变量也可以实现 执行后可以保留执行结果

        public SendMessage()
        {<!-- -->
            Console.WriteLine("SendMessage 被构造");
        }

        public async Task Execute(IJobExecutionContext context) //context 很强大  他会包含我们想要的切
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                //发消息:给谁发,需要传递参数;
                Console.WriteLine();
                Console.WriteLine("**********************************************");
                JobDataMap jobDetailMap = context.JobDetail.JobDataMap;

                Console.WriteLine($"{jobDetailMap.Get("Student1")}同学:准备开始上课了!{DateTime.Now}");
                Console.WriteLine($"{jobDetailMap.Get("Student2")}同学:准备开始上课了!{DateTime.Now}");
                Console.WriteLine($"{jobDetailMap.Get("Student3")}同学:准备开始上课了!{DateTime.Now}");
                Console.WriteLine($"{jobDetailMap.Get("Student4")}同学:准备开始上课了!{DateTime.Now}");
                Console.WriteLine($"{jobDetailMap.Get("Year")}");
                jobDetailMap.Put("Year", jobDetailMap.GetInt("Year") + 1);

                Console.WriteLine($"{jobDetailMap.Get("Student4")}同学:准备开始上课了!{DateTime.Now}");
                JobDataMap triggerMap = context.Trigger.JobDataMap;
                Console.WriteLine();

                Console.WriteLine($"{triggerMap.Get("Student5")}同学:第二次提示:准备开始上课了!{DateTime.Now}");
                Console.WriteLine($"{triggerMap.Get("Student6")}同学:第二次提示:准备开始上课了!{DateTime.Now}");
                Console.WriteLine($"{triggerMap.Get("Student7")}同学:第二次提示:准备开始上课了!{DateTime.Now}");
                Console.WriteLine($"{triggerMap.Get("Student8")}同学:第二次提示:准备开始上课了!{DateTime.Now}");

                Console.WriteLine($"{triggerMap.Get("Year")}");

                Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
                Console.WriteLine(context.MergedJobDataMap.Get("Year"));
                Console.WriteLine("**********************************************");
                Console.WriteLine();
            });
        }
    }

第二部分:框架日志和监听

执行代码

public static async Task Init()
        {<!-- -->

            #region 获取框架日志
            LogProvider.SetCurrentLogProvider(new CustomConsoleLogProvider());//
            #endregion

            #region Scheduler

            StdSchedulerFactory factory = new StdSchedulerFactory();
            IScheduler scheduler = await factory.GetScheduler();
            await scheduler.Start();



            #region Listener
            scheduler.ListenerManager.AddJobListener(new CustomJobListener());
            scheduler.ListenerManager.AddTriggerListener(new CustomTriggerListener());
            scheduler.ListenerManager.AddSchedulerListener(new CustomSchedulerListener());
            #endregion

            #endregion

            #region JobDetail
            IJobDetail jobDetail = JobBuilder.Create<SendMessage>()
                  .WithIdentity("sendJob", "group1")
                  .WithDescription("This is sendJob")
                  .Build();

            jobDetail.JobDataMap.Add("Student1", "阳光下的微笑");
            jobDetail.JobDataMap.Add("Student2", "明日梦");
            jobDetail.JobDataMap.Add("Student3", "大白");
            jobDetail.JobDataMap.Add("Student4", "池鱼");

            jobDetail.JobDataMap.Add("Year", DateTime.Now.Year);

            #endregion

            #region trigger

            //ITrigger trigger = TriggerBuilder.Create()
            //               .WithIdentity("sendTrigger", "group1")
            //               //.StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(10)))
            //               .StartNow()
            //              .WithCronSchedule("5/3 * * * * ?")//每隔一分钟 
            //              //5,8,11,14
            //              .WithDescription("This is sendJob's sendTrigger")
            //              .Build();

            ITrigger trigger = TriggerBuilder.Create()
                   .WithIdentity("sendTrigger", "group1")
                   .StartNow()
                   .WithSimpleSchedule(x => x
                       .WithIntervalInSeconds(10) //多少秒执行一次 
                       .WithRepeatCount(10) //表示最多执行多少次
                       .RepeatForever())
                       .WithDescription("This is testjob's Trigger")
                   .Build();

            trigger.JobDataMap.Add("Student5", "非常Nice");
            trigger.JobDataMap.Add("Student6", "Jerry");
            trigger.JobDataMap.Add("Student7", "龙");
            trigger.JobDataMap.Add("Student8", "月光寒");
            trigger.JobDataMap.Add("Year", DateTime.Now.Year + 1);

            #endregion 

            await scheduler.ScheduleJob(jobDetail, trigger);
        }
    }

监听Job,Trigger,Scheduler

public class CustomJobListener : IJobListener
    {<!-- -->
        public string Name => "CustomJobListener";

        public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                //便于我们自己添加自己的业务逻辑
                Console.WriteLine($"{DateTime.Now} this is JobExecutionVetoed");
            });
        }

        public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine($"{DateTime.Now} this is JobToBeExecuted");
            });
        }

        public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine($"{DateTime.Now} this is JobWasExecuted");
            });
        }
    }
public class CustomSchedulerListener : ISchedulerListener
    {<!-- -->
        public async Task JobAdded(IJobDetail jobDetail, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine($"{jobDetail.Description} 被加入到Scheduler");
            });
        }

        public async Task JobDeleted(JobKey jobKey, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine($"{jobKey} 被删除 ");
            });
        }

        public Task JobInterrupted(JobKey jobKey, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task JobPaused(JobKey jobKey, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task JobResumed(JobKey jobKey, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public async Task JobScheduled(ITrigger trigger, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine("this is JobScheduled");
            });
        }

        public Task JobsPaused(string jobGroup, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task JobsResumed(string jobGroup, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task JobUnscheduled(TriggerKey triggerKey, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task SchedulerError(string msg, SchedulerException cause, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task SchedulerInStandbyMode(CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task SchedulerShutdown(CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task SchedulerShuttingdown(CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public async Task SchedulerStarted(CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine($"this is SchedulerStarted");
            });
        }

        public async Task SchedulerStarting(CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine($"this is SchedulerStarting");
            });
        }

        public Task SchedulingDataCleared(CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task TriggerFinalized(ITrigger trigger, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task TriggerPaused(TriggerKey triggerKey, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task TriggerResumed(TriggerKey triggerKey, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task TriggersPaused(string triggerGroup, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }

        public Task TriggersResumed(string triggerGroup, CancellationToken cancellationToken = default)
        {<!-- -->
            throw new NotImplementedException();
        }
    }
public class CustomTriggerListener : ITriggerListener
    {<!-- -->
        public string Name => "CustomTriggerListener";

        public async Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- --> 
                Console.WriteLine("this is TriggerComplete");
            });
        }

        public async Task TriggerFired(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine("this is TriggerFired");
            });
        }

        public async Task TriggerMisfired(ITrigger trigger, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine("this is TriggerComplete");
            });
        }

        public async Task<bool> VetoJobExecution(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default)
        {<!-- -->
            await Task.Run(() =>
            {<!-- -->
                Console.WriteLine("VetoJobExecution");
            });
            return false;  //返回false才能继续执行
        }
    }

框架日志

public class CustomConsoleLogProvider : ILogProvider
    {<!-- -->
        public Logger GetLogger(string name) ///可以获取到框架内部的日志信息
        {<!-- -->
            return new Logger((level, func, exception, parameters) =>
            {<!-- -->
                if (level >= LogLevel.Info && func != null)
                {<!-- -->
                    Console.WriteLine($"[{ DateTime.Now.ToLongTimeString()}] [{ level}] { func()} {string.Join(";", parameters.Select(p => p == null ? " " : p.ToString()))}  自定义日志{name}");
                }
                return true;
            });
        }
        public IDisposable OpenNestedContext(string message)
        {<!-- -->
            throw new NotImplementedException();
        }

        public IDisposable OpenMappedContext(string key, string value)
        {<!-- -->
            throw new NotImplementedException();
        }
    }

第三部分:实现管理可视化

1.新建一个项目 3.访问:http://localhost:50611/CrystalQuartzPanel.axd
4.指定StdSchedulerFactory监控参数 端口和可视化项目的 webconfig 下的provider value 端口保持一直

原有项目代码

#region Scheduler

//StdSchedulerFactory factory = new StdSchedulerFactory();
//IScheduler scheduler = await factory.GetScheduler();
IScheduler scheduler = await ScheduleManager.BuildScheduler();
await scheduler.Start();
#endregion

ScheduleManager类

public class ScheduleManager
    {<!-- -->
        public async static Task<IScheduler> BuildScheduler()
        {<!-- -->
            var properties = new NameValueCollection();
            properties["quartz.scheduler.instanceName"] = "后台作业监控系统";

            // 设置线程池
            properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
            properties["quartz.threadPool.threadCount"] = "5";
            properties["quartz.threadPool.threadPriority"] = "Normal";

            // 远程输出配置
            properties["quartz.scheduler.exporter.type"] = "Quartz.Simpl.RemotingSchedulerExporter, Quartz";
            properties["quartz.scheduler.exporter.port"] = "8008";//端口必须和网站新项目端口一致
            properties["quartz.scheduler.exporter.bindName"] = "QuartzScheduler";
            properties["quartz.scheduler.exporter.channelType"] = "tcp";

            var schedulerFactory = new StdSchedulerFactory(properties);
            IScheduler _scheduler = await schedulerFactory.GetScheduler();
            return _scheduler;
        }
    }

第四部分:配置添加任务文件使用

主要改写的代码

//IJobDetail sayHijobDetail = JobBuilder.Create<SayHIJob>()
//    .WithDescription("this is sayHijobDetail")
//.WithIdentity("SayhiJob", "Vip高级班")
//.WithDescription("This is SayhiJob")
//.Build();

//ITrigger SayhiTrigger = TriggerBuilder.Create()
//               .WithIdentity("SayhiTrigger", "Vip高级班")
//               //.StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(10)))
//               .StartNow()
//              .WithCronSchedule("1/4 * * * * ?")  
//              .WithDescription("This is SayhiJob's SayhiTrigger")
//              .Build();

await scheduler.ScheduleJob(sayHijobDetail, SayhiTrigger);

//使用配置文件
XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper());
await processor.ProcessFileAndScheduleJobs("~/CfgFiles/quartz_jobs.xml", scheduler);

配置文件代码

<?xml version="1.0" encoding="UTF-8"?>
<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">

  <processing-directives>
    <overwrite-existing-data>true</overwrite-existing-data>
  </processing-directives>
  <schedule>
    <job>
      <name>SayhiJob</name>
      <group>Vip高级班</group>
      <description>this is sayHijobDetail</description>
      <job-type>DispatcherProject.QuartzNet.CustomJob.SayHIJob,DispatcherProject.QuartzNet</job-type>
      <durable>true</durable>
      <recover>false</recover>
    </job>
    <trigger>
      <cron>
        <name>SayhiJobTrigger</name>
        <group>Vip高级班</group>
        <job-name>SayhiJob</job-name>
        <job-group>Vip高级班</job-group>
        <cron-expression>0/3 * * * * ?</cron-expression>
      </cron>
    </trigger>


    <!--<job>
      <name>UpdateInventoryJob</name>
      <group>Update</group>
      <description>定时更新商品库存</description>
      <job-type>TopshelfAndQuartz.UpdateInventoryJob,TopshelfAndQuartz</job-type>
      <durable>true</durable>
      <recover>false</recover>
    </job>
    <trigger>
      <cron>
        <name>UpdateInventoryTrigger</name>
        <group>Update</group>
        <job-name>UpdateInventoryJob</job-name>
        <job-group>Update</job-group>
        <cron-expression>0 0/1 * * * ?</cron-expression>
      </cron>
    </trigger>-->
  </schedule>
</job-scheduling-data>

第五部分:解决应用程序池回收不生效的问题

WindowsService: 2.添加安装程序
3.就可以安装服务(可以通过工具)

public partial class Service1 : ServiceBase
    {<!-- -->

        Log4NetLogger log4NetLogger = new Log4NetLogger(typeof(Service1));
        public Service1()
        {<!-- -->
            InitializeComponent();
            DispatcherManager.Init().GetAwaiter().GetResult();
        }

        protected override void OnStart(string[] args)
        {<!-- -->
            log4NetLogger.Info("Service1  is Start");
        }

        protected override void OnStop()
        {<!-- -->
            log4NetLogger.Info("Service1  is Stop");
        }
    }

编译后进行服务安装
管理员身份打开

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil  D:\当前程序路径\bin\Debug\MyDispatcherProjectRichardWindowsService.exe


C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil /u  D:\当前程序路径\bin\Debug\MyDispatcherProjectRichardWindowsService.exe


服务改名称后,需要先原样卸载,再重新编译安装,要不然卸载还蛮麻烦的
上一篇:springboot Quartz动态修改cron表达式


下一篇:Quartz任务调度