这两天做一个实时任务推送,本来想着说用线程或者定时器。后面发现Quartz .net这个强大的定时任务框架,然后记录下
Quartz .Net就是一个定时任务推送的开源框架
下载地址:Quartz .net下载地址:https://www.quartz-scheduler.net/download.html
Quartz有两种存储机制,一是存缓存
1.配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file contains job definitions in schema version 2.0 format -->
<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>sampleJob</name>
<group>sampleGroup</group>
<description>Sample job for Quartz Server</description>
<job-type>Quartz.Server.SampleJob, Quartz.Server</job-type>
<durable>true</durable>
<recover>false</recover>
<job-data-map>
<entry>
<key>key1</key>
<value>value1</value>
</entry>
<entry>
<key>key2</key>
<value>value2</value>
</entry>
</job-data-map>
</job>
<trigger>
<simple>
<name>sampleSimpleTrigger</name>
<group>sampleSimpleGroup</group>
<description>Simple trigger to simply fire sample job</description>
<job-name>sampleJob</job-name>
<job-group>sampleGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<repeat-count>-1</repeat-count>
<repeat-interval>10000</repeat-interval>
</simple>
</trigger>
<trigger>
<cron>
<name>sampleCronTrigger</name>
<group>sampleCronGroup</group>
<description>Cron trigger to simply fire sample job</description>
<job-name>sampleJob</job-name>
<job-group>sampleGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<cron-expression>0/10 * * * * ?</cron-expression>
</cron>
</trigger>
<trigger>
<calendar-interval>
<name>sampleCalendarIntervalTrigger</name>
<group>sampleCalendarIntervalGroup</group>
<description>Calendar interval trigger to simply fire sample job</description>
<job-name>sampleJob</job-name>
<job-group>sampleGroup</job-group>
<misfire-instruction>SmartPolicy</misfire-instruction>
<repeat-interval>15</repeat-interval>
<repeat-interval-unit>Second</repeat-interval-unit>
</calendar-interval>
</trigger>
</schedule>
</job-scheduling-data>
2:定义Quartz任务管理工厂
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Berry.SignalRService.Schedu.Jobs
{
/// <summary>
/// Quartz任务管理类
/// </summary>
public static class QuartzUtil
{
private static ISchedulerFactory sf = null;
private static IScheduler sched = null;
static QuartzUtil()
{
sf = new StdSchedulerFactory();
sched = sf.GetScheduler();
sched.Start();
}
/// <summary>
/// 添加Job 并且以定点的形式运行 不带参数的cron表达式新建job
/// </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);
}
/// <summary>
/// 添加Job 并且以定点的形式运行 参数为Cron表达式,可传参数。目前支持一个参数,可加
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="JobName">keyName</param>
/// <param name="CronTime">Cron表达式</param>
/// <param name="jobDataMap">传递的参数,目前用于ConnId</param>
/// <returns></returns>
public static DateTimeOffset AddJob<T>(string JobName, string CronTime, string connIds) where T : IJob
{
IJobDetail jobCheck = JobBuilder.Create<T>().WithIdentity(JobName, JobName + "_Group").UsingJobData("connIds", connIds).Build();
ICronTrigger CronTrigger = new CronTriggerImpl(JobName + "_CronTrigger", JobName + "_TriggerGroup", CronTime);
return sched.ScheduleJob(jobCheck, CronTrigger);
}
/// <summary>
/// 添加Job 并且以周期的形式运行
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="JobName"></param>
/// <param name="SimpleTime">毫秒数</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));
}
/// <summary>
/// 添加Job 并且以周期的形式运行
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="JobName"></param>
/// <param name="SimpleTime">毫秒数</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>
/// 添加Job 并且以周期的形式运行
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="JobName"></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>
/// 添加Job 并且以周期的形式运行
/// </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, int SimpleTime, string MapKey, object MapValue) where T : IJob
{
Dictionary<string, object> map = new Dictionary<string, object>();
map.Add(MapKey, MapValue);
return AddJob<T>(JobName, StartTime, TimeSpan.FromMilliseconds(SimpleTime), map);
}
/// <summary>
/// 添加Job 并且以周期的形式运行
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="JobName">JobKey</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> map) where T : IJob
{
IJobDetail jobCheck = JobBuilder.Create<T>().WithIdentity(JobName, JobName + "_Group").Build();
jobCheck.JobDataMap.PutAll(map);
ISimpleTrigger triggerCheck = new SimpleTriggerImpl(JobName + "_SimpleTrigger", JobName + "_TriggerGroup",
StartTime,
null,
SimpleTriggerImpl.RepeatIndefinitely,
SimpleTime);
return sched.ScheduleJob(jobCheck, triggerCheck);
}
/// <summary>
/// 修改触发器时间,需要job名,以及修改结果
/// CronTriggerImpl类型触发器
/// </summary>
public static void UpdateTime(string jobName, string CronTime)
{
TriggerKey TKey = new TriggerKey(jobName + "_CronTrigger", jobName + "_TriggerGroup");
CronTriggerImpl cti = sched.GetTrigger(TKey) as CronTriggerImpl;
cti.CronExpression = new CronExpression(CronTime);
sched.RescheduleJob(TKey, cti);
}
/// <summary>
/// 修改触发器时间,需要job名,以及修改结果
/// SimpleTriggerImpl类型触发器
/// </summary>
/// <param name="jobName"></param>
/// <param name="SimpleTime">分钟数</param>
public static void UpdateTime(string jobName, int SimpleTime)
{
UpdateTime(jobName, TimeSpan.FromMinutes(SimpleTime));
}
/// <summary>
/// 修改触发器时间,需要job名,以及修改结果
/// SimpleTriggerImpl类型触发器
/// </summary>
public static void UpdateTime(string jobName, TimeSpan SimpleTime)
{
TriggerKey TKey = new TriggerKey(jobName + "_SimpleTrigger", jobName + "_TriggerGroup");
SimpleTriggerImpl sti = sched.GetTrigger(TKey) as SimpleTriggerImpl;
sti.RepeatInterval = SimpleTime;
sched.RescheduleJob(TKey, sti);
}
/// <summary>
/// 暂停所有Job
/// </summary>
public static void PauseAll()
{
sched.PauseAll();
}
/// <summary>
/// 恢复所有Job
/// </summary>
public static void ResumeAll()
{
sched.ResumeAll();
}
/// <summary>
/// 暂停某个任务
/// </summary>
/// <param name="JobName"></param>
public static void PauseJob(string JobName)
{
JobKey jk = new JobKey(JobName);
sched.PauseJob(jk);
}
/// <summary>
/// 恢复指定的Job
/// </summary>
/// <param name="JobKey"></param>
public static void ResumeJob(string JobName)
{
JobKey jk = new JobKey(JobName);
sched.ResumeJob(jk);
}
/// <summary>
/// 删除Job
/// </summary>
/// <param name="JobName"></param>
public static void DeleteJob(string JobName)
{
JobKey jk = new JobKey(JobName);
sched.DeleteJob(jk);
}
/// <summary>
/// 卸载定时器
/// </summary>
/// <param name="waitForJobsToComplete">是否等待job执行完成</param>
public static void Shutdown(bool waitForJobsToComplete)
{
sched.Shutdown(waitForJobsToComplete);
}
}
}
这个是我定义的Quartz的工厂类,写了几种方式的建立任务,一般来说都是用的cron表达式来建立的,因为呢这样比较方便,灵活。就是下面这个方式
public static DateTimeOffset AddJob <T>(string JobName,string CronTime,string connIds)其中T:IJob
{
IJobDetail jobCheck = JobBuilder.Create<T>().WithIdentity(JobName, JobName + "_Group").UsingJobData("connIds", connIds).Build();
ICronTrigger CronTrigger = new CronTriggerImpl(JobName + "_CronTrigger", JobName + "_TriggerGroup", CronTime);
return sched.ScheduleJob(jobCheck, CronTrigger);
}
IJobDetail是用于创建一个Job详情,包括Job名称,Job组,Job参数 “connIds”就是我传递的参数
ICronTrigger就是写入cron表达式的,关于cron表达式的格式参考下这个
https://blog.csdn.net/li295214001/article/details/52065634
然后工厂类就定义好了,其他的扩展方法还有很多,就没有一一说明了
3.定义Job
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Quartz;
using System.Collections.Generic;
namespace Berry.SignalRService.Schedu.Jobs
{
/// <summary>
/// 赛事推送
/// </summary>
public class MatchJob : IJob
{
/// <summary>
/// 系统缓存
/// </summary>
private readonly Cache.WebCache _cache = new Cache.WebCache();
private IHubConnectionContext<dynamic> Clients { get; set; }
private MatchJob(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
}
/// <summary>
/// 执行函数
/// </summary>
/// <param name="context"></param>
public void Execute(IJobExecutionContext context)
{
try
{
JobKey jobkey = context.JobDetail.Key;
//系统缓存的之前已经查出来的数据
var cachedata = _cache.GetCache<string>(jobkey.ToString() + "__JobDataCache");
//datamap里存的数据,现在是存的connid
string connIds = context.JobDetail.JobDataMap.GetString("connIds");
string[] connidList = connIds.Split(',');
//TODO 从数据库查询数据最新加的数据然后添加到__JobDataCache缓存
cachedata += "";
//将查出来的数据写入到缓存,覆盖之前的缓存
_cache.WriteCache(cachedata, jobkey.ToString() + "__JobDataCache");
//向所有开启服务的客户端推送查询到的数据
foreach (var connId in connidList)
{
Clients.Client(connId).BroadcastJobOpened(cachedata);
}
}
catch (System.Exception e)
{
throw new HubException("发送消息发生异常.", new { message = e.Message });
}
}
}
/// <summary>
/// 新闻推送
/// </summary>
public class NewsJob : IJob
{
/// <summary>
/// 系统缓存
/// </summary>
private readonly Cache.WebCache _cache = new Cache.WebCache();
private IHubConnectionContext<dynamic> Clients { get; set; }
private NewsJob(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
}
/// <summary>
/// 执行函数
/// </summary>
/// <param name="context"></param>
public void Execute(IJobExecutionContext context)
{
try
{
JobKey jobkey = context.JobDetail.Key;
//系统缓存的之前已经查出来的数据
var cachedata = _cache.GetCache<string>(jobkey.ToString() + "__JobDataCache");
//datamap里存的数据,现在是存的connid
string connIds = context.JobDetail.JobDataMap.GetString("connIds");
string[] connidList = connIds.Split(',');
//TODO 从数据库查询数据最新加的数据然后添加到__JobDataCache缓存
cachedata += "";
//将查出来的数据写入到缓存,覆盖之前的缓存
_cache.WriteCache(cachedata, jobkey.ToString() + "__JobDataCache");
//向所有开启服务的客户端推送查询到的数据
foreach (var connId in connidList)
{
Clients.Client(connId).BroadcastJobOpened(cachedata);
}
}
catch (System.Exception e)
{
throw new HubException("发送消息发生异常.", new { message = e.Message });
}
}
}
/// <summary>
/// 系统推送
/// </summary>
public class SysJob : IJob
{
/// <summary>
/// 系统缓存
/// </summary>
private readonly Cache.WebCache _cache = new Cache.WebCache();
private IHubConnectionContext<dynamic> Clients { get; set; }
private SysJob(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
}
/// <summary>
/// 执行函数
/// </summary>
/// <param name="context"></param>
public void Execute(IJobExecutionContext context)
{
try
{
JobKey jobkey = context.JobDetail.Key;
//系统缓存的之前已经查出来的数据
var cachedata = _cache.GetCache<string>(jobkey.ToString() + "__JobDataCache");
//datamap里存的数据,现在是存的connid
string connIds = context.JobDetail.JobDataMap.GetString("connIds");
string [] connidList = connIds.Split(',');
// TODO从数据库查询数据最新加的数据然后添加到__JobDataCache缓存
cachedata + =“”;
//将查出来的数据写入到缓存,覆盖之前的缓存 _cache.WriteCache(cachedata,jobkey.ToString()+“__ JobDataCache”);
//向所有开启服务的客户端推送查询到的数据 foreach(connidList中的var connId) { Clients.Client(CONNID).BroadcastJobOpened(cachedata); }
} catch(System.Exception e) { 抛出新的HubException(“发送消息发生异常。”,new {message = e.Message});
}
} } }
有几种类型的工作单独定义,执行函数可能不同。但是都要集成IJob类。
在执行函数里执行,可以获取到你传递的一个的JobDetail中的各个参数,用于你使用。
这样建立后就没有问题了,然后我用的实时推送是用的SignalR的直接推送给对应的用户的。做实时推送的话可以去看看,之后我也会更新一篇SignalR的用法~~
发现问题的欢迎大家指出来交流