隐藏

c# Quartzs定时器的简单使用

发布:2022/8/19 10:31:39作者:管理员 来源:本站 浏览次数:728

使用背景:


首先想到倒计时,定时任务。大家想到的肯定就是定时器。那么定时器在web和winfrom程序中有着很大的作用。那在服务器端有没有像定时器一样的存在呢。


有了这些需求,我找到了第三方的组件 Quartz.Net 来实现(源码位置:https://github.com/quartznet/quartznet)


(1)第一步,通过NuGet下载Quartz.Net组件并且引用到当前工程中


(2)创建两个类,一个是操作类,一个类继承IJob 并且需要实现IJob的方法。


   /// <summary>

   /// 操作类

   /// </summary>

   public class Operation : BaseBusiness<Auction>

   {


       #region 实例化


       public Operation()

       {

           _options = new Options();

       }


       internal IOptions _options { get; }


       #endregion


       public static IScheduler scheduler;

       public static ISchedulerFactory factory;

       /// <summary>

       /// 获取cron表达式

       /// </summary>

       /// <param name="time">时间</param>

       /// <returns></returns>

       public string GetCron(DateTime? time)

       {

           var txt = Convert.ToDateTime(time).ToString("yyyy-MM-dd-HH-mm-ss");

           var arr = txt.Split('-');

           var result = string.Format("{0} {1} {2} {3} {4} ? {5}", arr[5], arr[4], arr[3], arr[2], arr[1], arr[0]);

           return result;

       }

       /// <summary>

       /// 删除job

       /// </summary>

       /// <param name="Id">拍卖数据对象主键</param>

       /// <param name="GroupName">job的组名</param>

       public void RemoveJob(string Id, string MarkGoodsId, string GroupName)

       {

           //var jobKey = new JobKey(GroupName + Id + MId + "j", GroupName);

           var job = new JobKey(GroupName + Id + MarkGoodsId + "j", GroupName);

           scheduler.DeleteJob(job);

       }



       //清楚所有定时任务

       public void ClearJob()

       {

           if (scheduler != null)

           {

               scheduler.Clear();


           }

       }



   }

public class SetAuctionings : Operation, IJob

   {

       public async Task Execute(IJobExecutionContext context)

       {

           await Task.Run(() =>

           {


               DateTime freeTime = context.JobDetail.JobDataMap.GetDateTime("FreeTime");

               var now = DateTime.Now;


               //记录两个时间的差

               var days = freeTime.Subtract(now).Days;

               var hours = freeTime.Subtract(now).Hours;

               var minutes = freeTime.Subtract(now).Minutes;

               var seconds = freeTime.Subtract(now).Seconds;

               var result = days + "天" + hours + "时" + minutes + "分" + seconds + "秒";

//推送倒计时

               PushHelper.AuctionCountDown(markId, days, hours, minutes, seconds);






               //getTriggerState



           });

       }



/// <summary>

       /// 设置定时任务

       /// </summary>

       /// <param name="Id">标的ID</param>

       public void AddQz(DateTime BeginTime, DateTime FreeTime)

       {


           var GroupName = _options.GetPKById<Options_AuctionState>("1316283839361847296").ToString();

           factory = new StdSchedulerFactory();

           scheduler = factory.GetScheduler().Result;

           var jobKey = new JobKey(GroupName + Id + MId + "j", GroupName);

           var GjobDetail = scheduler.GetJobDetail(jobKey);

           if (GjobDetail != null)

           {

               //删除任务

               scheduler.DeleteJob(jobKey);

           }



           //设置Job  StatefulJob

           var job = JobBuilder.Create<SetAuctionings>()

                      .WithIdentity(GroupName + Id + MId + "j", GroupName)

                      .Build();




           job.JobDataMap.Put("FreeTime", FreeTime);

//【方法1】 设置每秒执行

           ITrigger trigger = TriggerBuilder.Create()

               .WithIdentity(GroupName + Id + MId + "t", GroupName)

               .WithSimpleSchedule(x => x.WithIntervalInSeconds(1)

               .RepeatForever())

               .StartAt(new DateTimeOffset(BeginTime))

               .EndAt(new DateTimeOffset(FreeTime))

               .Build();



           //【方法2】

           //var ExecSs = "0/1 * * * * ?";

           //ITrigger trigger = TriggerBuilder.Create()

           //    .WithIdentity(GroupName + Id + MeetingPlace + "t", GroupName)

           //    .WithCronSchedule(ExecSs)

           //    .StartAt(new DateTimeOffset(BeginTime))

           //    .EndAt(new DateTimeOffset(FreeTime))

           //    .Build();


           scheduler.ScheduleJob(job, trigger);

       }


   }

以上是一个简单的封装,可以根据这个倒计时的推送。增加一些封装 如:暂停,恢复,结束,更新等。


调用的话只需要简单的实例化一下进行调用。


然后我在大概说下其他封装的思路和代码片段;


延时倒计时:


根据传过来的参数时间进行一个修改,删除之前的任务重新开始一个任务;


/// <summary>

       /// 【拍卖延时】修改倒计时任务

       /// </summary>

       /// <param name="Id"></param>

       /// <param name="MeetingPlace"></param>

       /// <param name="FreeTime"></param>

       public void UpdateQz(String Id, string Mid, DateTime FreeTime, DateTime LimitTime)

       {



           //scheduler = factory.GetScheduler().Result;

           //if (scheduler == null)

           //    return;


           //拍卖进行中

           var GroupName = _options.GetPKById<Options_AuctionState>("1316283839361847296").ToString();

           var jobKey = new JobKey(GroupName + Id + Mid + "j", GroupName);

           var GjobDetail = scheduler.GetJobDetail(jobKey);

           if (GjobDetail.Result == null)

               return;



           var triggerKey = new TriggerKey(GroupName + Id + Mid + "t", GroupName);

           var triggerr = scheduler.GetTrigger(triggerKey);

           var triggerBuilder = triggerr.Result.GetTriggerBuilder();

           //修改结束时间 WithCronSchedule(ExecSs).

           ITrigger newTrigger = triggerBuilder.EndAt(new DateTimeOffset(FreeTime)).Build();




           var job = GjobDetail.Result;

           job.JobDataMap.Put("AuctionId", Id);

           job.JobDataMap.Put("MarkId", Mid);

           job.JobDataMap.Put("FreeTime", FreeTime);

           job.JobDataMap.Put("LimitTime", LimitTime);



           //删除任务

           scheduler.DeleteJob(jobKey);

           scheduler.ScheduleJob(job, newTrigger);



           //修改最终结束的定时任务;

           SetAuctioneds setAuctioneds = new SetAuctioneds();

           setAuctioneds.SetEndQz(Id, FreeTime, Mid);

       }



倒计时暂停:


调用组件的PauseTrigger方法可以进行暂停;

       /// <summary>

       /// 倒计时暂停

       /// </summary>

       public AjaxResult StopQz(string Id, string MId)

       {

           try

           {




               //方法1

               //拍卖进行中

               var GroupName = _options.GetPKById<Options_AuctionState>("1316283839361847296").ToString();




               var mark = Service.GetIQueryable<MarkGoods>().FirstOrDefault(x => x.Id == MId);

               if (mark == null)

                   return Error("找不到标的!");



               //获取实际结束时间。

               var subEndTime = mark.EndTime.Value;

               //计算暂停后剩余的时间  = audEndTime(结束时间) - 当前时间

               var nowEndTime = DateTime.Now;

               var DifferTime = subEndTime.Subtract(nowEndTime);


               //追加 剩余时间 和 当前结束时间;

               mark.SurplusTime = DifferTime.ToString();

               //mark.EndTime = nowEndTime;





               //GroupName + Id + MId + "t", GroupName

               var TriKey = new TriggerKey(GroupName + Id + MId + "t", GroupName);



               var Result = scheduler.GetTriggerState(TriKey).Result;

               if (Result == TriggerState.None)

               {

                   return Error("失败:不存在此任务!");

               }



               if (Result == TriggerState.Paused)//暂停

               {

                   return Success("失败:该任务已暂停!");


               }

               else

               {

                   scheduler.PauseTrigger(TriKey);

                   mark.AucTimeStatus = 2;

                   Service.UpdateAny<MarkGoods>(mark, new List<string> { "SurplusTime", "AucTimeStatus" });

                   return Success("成功:任务已暂停");

               }





               //方法2

               //var mark = Service.GetIQueryable<MarkGoods>().FirstOrDefault(x => x.Id == MId);

               //if (mark == null)

               //    return;



               ////获取实际结束时间。

               //var subEndTime = mark.EndTime.Value;

               ////计算暂停后剩余的时间  = audEndTime(结束时间) - 当前时间

               //var nowEndTime = DateTime.Now;

               //var DifferTime = subEndTime.Subtract(nowEndTime);


               ////追加 剩余时间 和 当前结束时间;

               //mark.SurplusTime = DifferTime.ToString();

               ////mark.EndTime = nowEndTime;

               //Service.UpdateAny<MarkGoods>(mark, new List<string> { "SurplusTime" });




               ////拍卖进行中

               //var GroupName = _options.GetPKById<Options_AuctionState>("1316283839361847296").ToString();

               ////关闭该定时器

               //RemoveJob(mark.AuctionId, mark.Id, GroupName);


           }

           catch (Exception)

           {


               throw;

           }



       }



倒计时恢复:


俗话说得好破镜难圆,泼出去的水很难收回来。恢复也是这个道理,比如:倒计时走到了7暂停,那么恢复的时候如何从7继续呢。这里就牵扯到了时间戳并且存入数据库的介入了。


       /// <summary>

       /// 恢复倒计时

       /// </summary>

       public AjaxResult ReturnQz(string Id, string MId)

       {

           try

           {



               var mark = Service.GetIQueryable<MarkGoods>().FirstOrDefault(x => x.Id == MId);

               if (mark == null)

                   return Error();

               //获取实际结束时间。

               if (mark.SurplusTime.IsNullOrEmpty())

               {

                   return Error();

               }

               TimeSpan.TryParse(mark.SurplusTime, out TimeSpan surplusTime);

               //方法1

               //拍卖进行中

               //拍卖进行中

               var GroupName = _options.GetPKById<Options_AuctionState>("1316283839361847296").ToString();

               var TriKey = new TriggerKey(GroupName + Id + MId + "t", GroupName);


               var Result = scheduler.GetTriggerState(TriKey).Result;

               if (Result == TriggerState.None)

               {

                   return Error("失败:不存在此任务!");

               }

               if (Result == TriggerState.Normal)//暂停

               {

                   return Error("失败:任务正在进行,无需恢复!");


               }

               else

               {


                   //结束时间  = 当前时间 + 剩余时间

                   var endTime = DateTime.Now.Add(surplusTime);

                   //获取限时竞价时间

                   var LimitTime = endTime.AddHours(-mark.LimitHH.Value).AddMinutes(-mark.LimitMM.Value).AddSeconds(-mark.LimitSS.Value);

                   //修改倒计时任务;

                   UpdateQz(mark.AuctionId, mark.Id, endTime, LimitTime);



                   //追加 剩余时间 和 当前结束时间;

                   mark.SurplusTime = "";

                   mark.EndTime = endTime;

                   var C1 = endTime.Subtract(DateTime.Now);

                   var C2 = endTime.Subtract(LimitTime);

                   if (C1 > C2)

                       mark.AucTimeStatus = 0;

                   else

                       mark.AucTimeStatus = 1;

                   Service.UpdateAny<MarkGoods>(mark, new List<string> { "SurplusTime", "EndTime", "AucTimeStatus" });


                   return Success();



               }









               //方法2

               //var mark = Service.GetIQueryable<MarkGoods>().FirstOrDefault(x => x.Id == MId);

               //if (mark == null)

               //    return;



               ////获取实际结束时间。

               //if (mark.SurplusTime.IsNullOrEmpty())

               //{

               //    return;

               //}

               //TimeSpan.TryParse(mark.SurplusTime, out TimeSpan surplusTime);

               //TimeSpan a = new TimeSpan(1, 1, 1);

               ////结束时间  = 当前时间 + 剩余时间

               //var endTime = DateTime.Now.Add(surplusTime);

               ////获取限时竞价时间

               //var LimitTime = endTime.AddHours(-mark.LimitHH.Value).AddMinutes(-mark.LimitMM.Value).AddSeconds(-mark.LimitSS.Value);

               ////新增倒计时任务;

               //AddQz(mark.AuctionId, mark.Id, DateTime.Now, endTime, LimitTime);



               ////追加 剩余时间 和 当前结束时间;

               //mark.SurplusTime = "";

               //mark.EndTime = endTime;

               //Service.UpdateAny<MarkGoods>(mark, new List<string> { "SurplusTime", "EndTime" });



           }

           catch (Exception ex)

           {


               throw;

           }


       }

以上代码均是提供思路,需要进行代码简单改动。