当前位置: 首页 > 工具软件 > Quartz EX > 使用案例 >

Quartz.net的自定义接口,增删改查,可视化,远程调度

东方宜
2023-12-01

Quartz.net

Quartz是一个开源的作业调度框架,OpenSymphony的开源项目。Quartz.Net 是Quartz的C#移植版本。

基础概念

Scheduler 调度器。
IJob 任务,所有的定时作业都需要继承该类
  IJobDetail 给定作业实例的详细属性
  JobKey Quartz.IJobDetail的唯一标识
ITrigger 触发器,支持cron和简单基础时间
  TriggerKey ITrigger 的唯一标识

例子

public class DayJobs : IJob
    {
        protected ILogger _logger;//日志,不做过多介绍
        protected ILogger logger
        {
            get
            {
                if (_logger == null)
                    _logger = IocContainer.Resolve<ILoggerFactory>().Create(this.GetType());
                return _logger;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public DayJobs()
        {
            _policySdk = new PolicySdkFactory();
        }

        /// <summary>
        /// 执行,必须实现此方法
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Execute(IJobExecutionContext context)
        {

            try
            {
                //test
                var test="test";//可打断点直接调试,不做过多处理
            }
            catch (Exception ex)
            {
                logger.Error("执行每日任务错误", this.GetType().FullName, ex);
            }
            await Task.FromResult(true);
        }

    }

基础配置文件

在此之前需要引用相关nuget,Quartz,Quartz.Jobs,Quartz.Plugins,注意版本,需要对应项目net版本
基础配置可以直接于代码中配置,也可以读取配置文件数据,推荐使用配置文件。

//第一步:在web.config <configSections>中加入如下配置
<configSections>
<section name="quartz" type="System.Configuration.NameValueSectionHandler" />
</configSections>
//第二步:定义如下配置
 <quartz>
    <!-- 定时调度相关配置 -->
    <!--可视化配置-->
    <!--<add key="quartz.scheduler.exporter.port" value="555" />
    <add key="quartz.scheduler.exporter.bindName" value="QuartzScheduler" />
    <add key="quartz.scheduler.exporter.channelType" value="tcp" />
    <add key="quartz.scheduler.exporter.type" value="Quartz.Simpl.RemotingSchedulerExporter, Quartz" />-->
    
    <!--******************************使用xml配置读取作业*********************************************-->
    <add key="quartz.plugin.xml.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin,Quartz.Plugins" />
    <add key="quartz.plugin.xml.fileNames" value="~/Configs/quartz_jobs.xml" /><!--相对路径-->
    <!--<add key="quartz.scheduler.instanceId" value="AUTO"/>
    <add key="quartz.scheduler.instanceName" value="调度监控系统"/>-->
    <!--线程池--><!--
    <add key="quartz.threadPool.type" value=""/>
    --><!--线程数量--><!--
    <add key="quartz.threadPool.threadCount" value=""/>
    --><!--线程优先级--><!--
    <add key="quartz.threadPool.threadPriority" value=""/>-->
  </quartz>
  //第三步 具体的作业和定时器定义 quartz_jobs.xml
  <?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唯一-->
      <name>每日任务</name>
      <!--任务所属分组【选填】-->
      <group>调度</group>
      <!--任务描述【选填】-->
      <description>定时任务</description>
      <!--任务类型【必填】:实现IJob接口,具体到命名空间的类名,程序集名(dll)-->
      <job-type>Platform.Infrastructure.Schedulers.Jobs.DayJobs, Platform.Infrastructure</job-type>
      <!--默认true-->
      <durable>true</durable>
      <!--默认false-->
      <recover>false</recover>
    </job>

    <!--触发器,可添加多个-->
    <trigger>
      <!--simple:简单触发器类型,cron:复杂触发器类型-->
      <cron>
        <!--触发器名称【必填】:通与ob一样,同分组中也是唯一的-->
        <name>日触发器</name>
        <!--触发器组【选填】-->
        <group>触发器</group>
        <!--触发器描述【选填】-->
        <description>每天的23:30发生</description>
        <!--要调度的任务名称【必填】:必须和对应job节点中的name-->
        <job-name>每日任务</job-name>
        <!--要调度的任务的所属分组【选填】:必须和对应job节点中的group-->
        <job-group>调度</job-group>
        <cron-expression>0 30 23 * * ? </cron-expression><!--在线生成cron地址https://cron.qqe2.com/-->
      </cron>

    </trigger>
    <!--结束一个调度-->
  </schedule>
</job-scheduling-data>


Scheduler的定义和启用

定义

public  class SchedulerBase
    {
        /// <summary>
        /// 调度器基础配置
        /// </summary>
        public static Task<IScheduler> Scheduler
        {
            get
            {
                //已经调整为读取配置文件
                NameValueCollection props = new NameValueCollection();
                props["quartz.scheduler.instanceId"] = Configs.GetValue("quartz.scheduler.instanceId");
                props["quartz.scheduler.instanceName"] = Configs.GetValue("quartz.scheduler.instanceName");

                //可视化端口
                //props["quartz.scheduler.exporter.port"] = Configs.GetValue("quartz.scheduler.exporter.port");
                //props["quartz.scheduler.exporter.bindName"] = Configs.GetValue("quartz.scheduler.exporter.bindName");
                //props["quartz.scheduler.exporter.channelType"] = Configs.GetValue("quartz.scheduler.exporter.channelType");  			//协议类型
                //props["quartz.scheduler.exporter.type"] = Configs.GetValue("quartz.scheduler.exporter.type");
                
                var scheduler = StdSchedulerFactory.GetDefaultScheduler();

                return scheduler;
            }

        }

        public static  ITrigger AddTrigger(SchedulerReq model)
        {
            ITrigger dayJobTrigger = TriggerBuilder.Create()
               .WithIdentity(model.TriggerName, model.TriggerGroup)
              .WithDescription(model.TriggerDescription)
               .StartNow()
               .WithCronSchedule(model.CronSchedule)
               .Build();
            return dayJobTrigger;
        }
    }


public class SchedulerMain 
    {

        private static IScheduler scheduler;
        /// <summary>
        /// 定时调度任务
        /// </summary>
        public SchedulerMain()
        {

        }
        public void Start()
        {
            Init().Wait();
        }
        public async Task Init()
        {
            scheduler = await SchedulerBase.Scheduler;
          // await scheduler.GetJobGroupNames();
            //启动调度器
            await scheduler.Start();
            //执行调度
            //await SchedulerBase.AddSchedule(
            //    new Jobs.JobServer<Jobs.DayJobs>(),
            //    new Triggers.DayTrigger().SendTrigger(),
            //    "每日任务", "调度");
        }
        
        public void Stop()
        {
            Shutdown().Wait();
        }
        public async Task Shutdown()
        {
            if (scheduler != null)
                await scheduler.Shutdown();
        }

        public static IScheduler GetScheduler()
        {
            return scheduler;
        }
    }

启用
Global.asax中的Application_Start中进行Start,就完成了基础的使用

protected void Application_Start()
{
	New SchedulerMain().Start();
}

定义相关类

 /// <summary>
   /// 请求参数
   /// </summary>
 public  class SchedulerReq
    {
        /// <summary>
        /// 作业名称
        /// </summary>
        public string JobName { get; set; }
        /// <summary>
        /// 作业分组
        /// </summary>
        public string JobGroup { get; set; }
        /// <summary>
        /// 间隔(Cron)
        /// </summary>
        public string CronExpression { get; set; }
        /// <summary>
        /// 调度器描述
        /// </summary>
        public string TriggerDescription { get; set; }
        /// <summary>
        /// 调度器名称
        /// </summary>
        public string TriggerName { get; set; }
        /// <summary>
        /// 调度器所属分组
        /// </summary>
        public string TriggerGroup { get; set; }
        /// <summary>
        /// 运行频率
        /// </summary>
        public string CronSchedule { get; set; }
        /// <summary>
        /// 程序集
        /// </summary>
        public string AssemblyName { get; set; }
        /// <summary>
        /// 命名空间加job所在类名
        /// </summary>
        public string ClassName { get; set; }
    }


/// <summary>
    /// 结果
    /// </summary>
    public class SchedulerResult
    {
        /// <summary>
        /// 作业名称
        /// </summary>
        public string JobName { get; set; }
        /// <summary>
        /// 作业分组
        /// </summary>
        public string JobGroup { get; set; }
        /// <summary>
        /// 作业描述
        /// </summary>
        public string JobDescription { get; set; }
        /// <summary>
        /// 创建
        /// </summary>
        public DateTime? CreateTime { get; set; }
        /// <summary>
        /// 最后执行时间
        /// </summary>
        public DateTime? LastRunTime { get; set; }
        /// <summary>
        /// 下次执行时间
        /// </summary>
        public DateTime? NextRunTime { get; set; }
        /// <summary>
        /// 间隔(Cron)
        /// </summary>
        public string CronExpression { get; set; }
        /// <summary>
        /// 调度器描述
        /// </summary>
        public string TriggerDescription { get; set; }
        /// <summary>
        /// 调度器名称
        /// </summary>
        public string TriggerName { get; set; }
        /// <summary>
        /// 调度器所属分组
        /// </summary>
        public  string TriggerGroup { get; set; }
        /// <summary>
        /// 任务当前状态
        /// </summary>
        public string TriggerState { get; set; }
        /// <summary>
        /// 程序集
        /// </summary>
        public string AssemblyName { get; set; }
        /// <summary>
        /// 命名空间加job所在类名
        /// </summary>
        public string ClassName { get; set; }
    }

相关接口,具体的数据获取和增删改查

暂未关联数据库,后期会逐步与数据库关联

public class SchedulerApi
    {
        private static IScheduler scheduler;
        public SchedulerApi()
        {
            scheduler = SchedulerBase.Scheduler.Result;
        }
        /// <summary>
        /// 获取任务列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<SchedulerResult>> GetJobs()
        {
            var list = new List<SchedulerResult>();
            var groups = await scheduler.GetJobGroupNames();
            foreach (var groupName in groups)
            {
                foreach (var jobKey in await scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName)))
                {
                    var taskOptions = new SchedulerResult();
                    var job = scheduler.GetJobDetail(jobKey);
                    taskOptions.JobDescription = job.Result.Description;
                    taskOptions.JobName = jobKey.Name;
                    taskOptions.JobGroup = jobKey.Group;
                    taskOptions.AssemblyName = job.Result.JobType.Assembly.GetName().Name;
                    taskOptions.ClassName = job.Result.JobType.FullName;
                    var triggers = await scheduler.GetTriggersOfJob(jobKey);
                    foreach (CronTriggerImpl trigger in triggers)
                    {
                        //最后执行时间
                        DateTimeOffset? dateTimePreviousOffset = trigger.GetPreviousFireTimeUtc();
                        //下次执行时间
                        DateTimeOffset? dateTimeNextOffset = trigger.GetNextFireTimeUtc();
                        DateTimeOffset? createTime = trigger.StartTimeUtc;
                        if (dateTimePreviousOffset != null)
                            taskOptions.LastRunTime = TimeZoneInfo.ConvertTimeFromUtc(dateTimePreviousOffset.Value.DateTime, TimeZoneInfo.Local);
                        if (dateTimeNextOffset != null)
                            taskOptions.NextRunTime = TimeZoneInfo.ConvertTimeFromUtc(dateTimeNextOffset.Value.DateTime, TimeZoneInfo.Local);
                        if (createTime != null)
                            taskOptions.CreateTime = TimeZoneInfo.ConvertTimeFromUtc(createTime.Value.DateTime, TimeZoneInfo.Local);
                        taskOptions.TriggerDescription = trigger.Description;
                        taskOptions.TriggerName = trigger.Key.Name;
                        taskOptions.TriggerGroup = trigger.Key.Group;
                        taskOptions.TriggerState = ((ETriggerState)(int)scheduler.GetTriggerState(trigger.Key).Result).ToString();
                        taskOptions.CronExpression = trigger.CronExpressionString;
                        list.Add(taskOptions);
                        
                    }
                    
                }
            }
            return list;
        }
        /// <summary>
        /// 添加任务(可自己进行部分修改,例如使用异步,返回不同参数等)
        /// </summary>
        /// <param name="model"></param>
        public void AddJobs(SchedulerReq model)
        {
            if (!ValidExpression(model.CronSchedule)) Ensure.Error("运行频率,【Cron】表达式设置错误!");
            ITrigger trigger = SchedulerBase.AddTrigger(model);
            JobKey jk = new JobKey(model.JobName, model.JobGroup);
            if (scheduler.CheckExists(jk).Result)
            {
                Ensure.Error($"任务{model.JobName}已存在!");
            }
            else
            {
                Assembly assembly = Assembly.Load(model.AssemblyName);
                Type type = assembly.GetType(model.ClassName);
                if (type == null) Ensure.Error("Job类错误!");
                IJobDetail job = JobBuilder.Create(type).WithIdentity(model.JobName, model.JobGroup).Build();

                scheduler.ScheduleJob(job, trigger);
            }

        }
        /// <summary>
        /// 删除任务
        /// </summary>
        /// <param name="model"></param>
        public  void DeleteJob(SchedulerReq model)
        {
            ITrigger trigger = SchedulerBase.AddTrigger(model);
            JobKey jk = new JobKey(model.JobName, model.JobGroup);
            if ( scheduler.CheckExists(jk).Result)
            {
                 scheduler.DeleteJob(jk);
            }
            else
            {
                Ensure.Error($"任务{model.JobName}不存在!");
            }

        }
        /// <summary>
        /// 继续任务
        /// </summary>
        /// <param name="model"></param>
        public  void ResumeJob(SchedulerReq model)
        {

            JobKey jk = new JobKey(model.JobName, model.JobGroup);
            if ( scheduler.CheckExists(jk).Result)
            {
                //任务已经存在则继续任务
                 scheduler.ResumeJob(jk);
            }
        }
        /// <summary>
        /// 暂停任务
        /// </summary>
        /// <param name="model"></param>
        public  void PauseJob(SchedulerReq model)
        {

            JobKey jk = new JobKey(model.JobName, model.JobGroup);
            if ( scheduler.CheckExists(jk).Result)
            {
                //任务已经存在则暂停任务
                 scheduler.PauseJob(jk);
            }
        }
        /// <summary>
        /// 更新任务
        /// </summary>
        /// <param name="model"></param>
        public void UpdateJob(SchedulerReq model)
        {

            JobKey jk = new JobKey(model.JobName, model.JobGroup);
            if (scheduler.CheckExists(jk).Result)
            {
                var triggers = scheduler.GetTriggersOfJob(jk).Result;
                ITrigger trigger = triggers?.Where(x => (x as CronTriggerImpl).Name == model.TriggerName).FirstOrDefault();
                scheduler.PauseTrigger(trigger.Key);
                scheduler.UnscheduleJob(trigger.Key);// 移除触发器
                scheduler.DeleteJob(jk);
                AddJobs(model);
            }
        }
        /// <summary>
        /// 立即执行
        /// </summary>
        /// <param name="model"></param>
        public void RunJob(SchedulerReq model)
        {
            JobKey jk = new JobKey(model.JobName, model.JobGroup);
            if (scheduler.CheckExists(jk).Result)
            {
                //任务已经存在则立即执行
                scheduler.TriggerJob(jk);
            }
        }
        /// <summary>
        /// 启动任务调度
        /// </summary>
        /// <param name="model"></param>
        public async void StartSchedule()
        {

            if (!scheduler.IsStarted)
            {
                //等待任务运行完成
                await scheduler.Start();
            }
        }
        /// <summary>
        /// 停止任务调度
        /// </summary>
        /// <param name="model"></param>
        public async void StopSchedule()
        {
            
            if (!scheduler.IsShutdown)
            {
                //等待任务运行完成
               await scheduler.Shutdown(false);
            }
        }

        /// <summary>
        /// 校验字符串是否为正确的Cron表达式
        /// </summary>
        /// <param name="cronExpression">带校验表达式</param>
        /// <returns></returns>
        public  bool ValidExpression(string cronExpression)
        {
            return CronExpression.IsValidExpression(cronExpression);
        }
        /// <summary>
        /// 验证是否存在任务
        /// </summary>
        /// <param name="name"></param>
        /// <param name="group"></param>
        /// <returns></returns>
        public bool CheckExists(string name, string group)
        {
            JobKey jk = new JobKey(name, group);
            return scheduler.CheckExists(jk).Result;
        }
    }

webapi接口使用

直接在控制器中使用即可,只例举获取,其它接口同

public class SchedulerController:BaseController{
		private readonly SchedulerApi _schedulerApi;
	        public SchedulerController()
	        {
	            _schedulerApi = new SchedulerApi();
	        }
	        /// <summary>
        /// 获取任务列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("GetJobs")]
        [SwaggerResponse(200, "成功返回参数", type: typeof(SchedulerResult))]
        public IHttpActionResultGetJobs() {

            var list = _schedulerApi.GetJobs().Result;
            return Success(list);
        }
}

参考链接:
https://www.cnblogs.com/zixuan9527/p/8601151.html
https://github.com/weizhong1988/Weiz.TaskManager/blob/master/Weiz.TaskManager.TaskUtility/Quartz/QuartzHelper.cs

 类似资料: