zoukankan      html  css  js  c++  java
  • QuartzNet3.0实现作业调度

    Quartz是一个完全由JAVA编写的开源作业调度框架。

    Quartz.NET是Quartz的.NET移植,它用C#写成,可用于.Net以及.Net Core的应用中。

    目前最新的quartz.net版本3.0.6 只支持.netframework4.5.2及.netstandard2.0及以上版本

    官方实例:https://www.quartz-scheduler.net/documentation/quartz-3.x/quick-start.html

    using Quartz;
    using Quartz.Impl;
    using Quartz.Logging;
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Demo
    {
        class Program
        {
            private static void Main(string[] args)
            {
                LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());
    
                RunProgramRunExample().GetAwaiter().GetResult();
    
                Console.WriteLine("Press any key to close the application");
                Console.ReadKey();
            }
    
            private static async Task RunProgramRunExample()
            {
                try
                {
                    // Grab the Scheduler instance from the Factory
                    NameValueCollection props = new NameValueCollection
                    {
                        { "quartz.serializer.type", "binary" }
                    };
                    StdSchedulerFactory factory = new StdSchedulerFactory(props);
                    IScheduler scheduler = await factory.GetScheduler();
    
                    // and start it off
                    await scheduler.Start();
    
                    // define the job and tie it to our HelloJob class
                    IJobDetail job = JobBuilder.Create<HelloJob>()
                        .WithIdentity("job1", "group1")
                        .Build();
    
                    // Trigger the job to run now, and then repeat every 10 seconds
                    ITrigger trigger = TriggerBuilder.Create()
                        .WithIdentity("trigger1", "group1")
                        .StartNow()
                        .WithSimpleSchedule(x => x
                            .WithIntervalInSeconds(10)
                            .RepeatForever())
                        .Build();
    
                    // Tell quartz to schedule the job using our trigger
                    await scheduler.ScheduleJob(job, trigger);
    
                    // some sleep to show what's happening
                    await Task.Delay(TimeSpan.FromSeconds(60));
    
                    // and last shut down the scheduler when you are ready to close your program
                    await scheduler.Shutdown();
                }
                catch (SchedulerException se)
                {
                    Console.WriteLine(se);
                }
            }
    
            // simple log provider to get something to the console
            private class ConsoleLogProvider : ILogProvider
            {
                public Logger GetLogger(string name)
                {
                    Logger loger = LoggerMethod;
                    return loger;
    
                    return (level, func, exception, parameters) =>
                    {
                        if (level >= LogLevel.Info && func != null)
                        {
                            Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);
                        }
                        return true;
                    };
                }
    
                private bool LoggerMethod(LogLevel logLevel, Func<string> messageFunc, Exception exception = null, params object[] formatParameters)
                {
                    if (logLevel >= LogLevel.Info && messageFunc != null)
                    {
                        Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + logLevel + "] " + messageFunc(), formatParameters);
                    }
                    return true;
                }
    
                public IDisposable OpenNestedContext(string message)
                {
                    throw new NotImplementedException();
                }
    
                public IDisposable OpenMappedContext(string key, string value)
                {
                    throw new NotImplementedException();
                }
            }
        }
    
        public class HelloJob : IJob
        {
            public async Task Execute(IJobExecutionContext context)
            {
                await Console.Out.WriteLineAsync("Greetings from HelloJob!");
            }
        }
    
    }
    View Code

    看了这个官方的示例,你会发现QuarztNet3.0版本较之2.0版本,引入了async/await

    下面记录一下学习过程:

    一、使用VS2013新建Winform项目,.Net版本为4.5.2,通过Nuget命令行获取Quarzt.Net:Install-Package Quartz. 如果你在安装过程中报错,那么,要注意你的.Net版本

    二、万事俱备,开始编码

    多任务,一个每分钟的第30秒播放音频,一个每分钟的第0秒写文本文件

    private async void PlaySound()
    {
        //1.通过工厂获取一个调度器的实例
        StdSchedulerFactory factory = new StdSchedulerFactory();
        _scheduler = await factory.GetScheduler();
        await _scheduler.Start();
    
        //创建任务对象
        IJobDetail job = JobBuilder.Create<SoundJob>()
            .WithIdentity("job1", "group1")
            .Build();
    
    
        //创建触发器
        ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity("trigger1", "group1")
            .StartNow()
            .WithCronSchedule("30 0/1 * * * ?")//每分钟的第30秒执行
            .Build();
    
        //将任务加入到任务池
        await _scheduler.ScheduleJob(job, trigger);
    
        job = JobBuilder.Create<PrintJob>()
         .WithIdentity("job2", "group1")
         .Build();
    
        trigger = TriggerBuilder.Create()
            .WithIdentity("trigger2", "group1")
            .StartNow()
            .WithCronSchedule("0 0/1 * * * ?")//每分钟的第0秒执行
            .Build();
    
        await _scheduler.ScheduleJob(job, trigger);
    }
    public class PrintJob : IJob
    {
        string fileName = "printlog.txt";
        public Task Execute(IJobExecutionContext context)
        {
            StreamWriter writer = new StreamWriter(fileName, true);
            Task task = writer.WriteLineAsync(string.Format("{0}", DateTime.Now.ToLongTimeString()));
            writer.Close();
            writer.Dispose();
            return task;
        }
    }
    public class SoundJob : IJob
    {
        public static Action<string> _printLogCallBack;
    
        public string Sound { get; set; }
    
        public Task Execute(IJobExecutionContext context)
        {
            JobDataMap jobDataMap = context.JobDetail.JobDataMap;
            string sound = jobDataMap.GetString("sound");
            int number = jobDataMap.GetInt("number");
    
            if (_printLogCallBack != null)
            { _printLogCallBack(string.Format("{0}[{1}] 执行任务 Sound {2}", Environment.NewLine, DateTime.Now.ToLongTimeString(), Sound)); }
    
            return Task.Factory.StartNew(() =>
            {
                SoundPlayer player = new SoundPlayer();
                player.SoundLocation = @"F:FFOutput421204264234974-.wav";
                player.Load();
                player.Play();
            });
        }
    }

    以上是主要部分,另外还涉及到日志部分,日志我是直接输出到UI上,我们可以看到以下编码的区别,ConsoleLogProvider中输出的日志可以直接打印,而SoundJob中的却不可以,说明SoundJob中的方法是异步执行的,需要解决跨线程访问UI控件的问题,我们可以使用UI线程的上下文对象SynchronizationContext _syncContext,将输出日志的方法,委托给UI线程执行。

    private void Form1_Load(object sender, EventArgs e)
    {
        ConsoleLogProvider logProvider = new ConsoleLogProvider();
        logProvider.SetLogCallBack((log) =>
        {
            this.rchMessage.AppendText(log);
        });
    
        SoundJob._printLogCallBack = (log) =>
        {
            _syncContext.Send((obj) =>
            {
                this.rchMessage.AppendText(log.ToString());
            }, null);
        };
    
        LogProvider.SetCurrentLogProvider(logProvider);
    }

    关于Cron表达式:

    /*
    由7段构成:秒 分 时 日 月 星期 年(可选)
    
    "-" :表示范围  MON-WED表示星期一到星期三
    "," :表示列举 MON,WEB表示星期一和星期三
    "*" :表是“每”,每月,每天,每周,每年等
    "/" :表示增量:0/15(处于分钟段里面) 每15分钟,在0分以后开始,3/20 每20分钟,从3分钟以后开始
    "?" :只能出现在日,星期段里面,表示不指定具体的值
    "L" :只能出现在日,星期段里面,是Last的缩写,一个月的最后一天,一个星期的最后一天(星期六)
    "W" :表示工作日,距离给定值最近的工作日
    "#" :表示一个月的第几个星期几,例如:"6#3"表示每个月的第三个星期五(1=SUN...6=FRI,7=SAT)
    
    如果Minutes的数值是 '0/15' ,表示从0开始每15分钟执行
    
    如果Minutes的数值是 '3/20' ,表示从3开始每20分钟执行,也就是‘3/23/43’
    */

    运行效果图:

  • 相关阅读:
    配置文件中文件重复
    大型网站技术架构02
    2018.12.26-12.30第一周毕设计划
    软件架构模式-分层架构II
    软件架构模式-分层架构
    echarts实现中国地图数据展示
    Python数据分析入门(一)——了解Python下的函数包
    Python学习笔记(二)
    Python学习笔记(一)
    Echarts的简单使用
  • 原文地址:https://www.cnblogs.com/dwBurning/p/QuartzNet.html
Copyright © 2011-2022 走看看