Quartz.Net定时任务EF+MVC版的web服务

    之前项目采用JAVA 的 Quartz 进行定时服调度务处理程序,目前在.NET下面使用依然可以完成相同的工作任务,其实什么语言不重要,关键是我们要学会利用语言实现价值。它是一个简单的执行任务计划的组件,基本包括这三部分:Job(作业)、Trigger(触发器)、scheduler(调度器)。

       1.Job 作业:需要在任务计划中执行的具体逻辑操作

        2.Trigger 触发器:需要什么时间什么规则来去执行Job 作业

        3.scheduler 调度器 :将Job 和 Trigger 注册到 scheduler 调度器中,主要负责协调Job、Trigger 的运行

.NET可以做成服务端方式也可以做成web端处理,本方法是采用web的方式处理,话不多说直接上干活。在这里借鉴了别人的方式但是别人的有些很多漏洞和错误,我也进行了抛砖引玉加以完善。

首先先创建一个新项目,新建一个类库JobLibrary项目库:

一个Job 创建一个实例类,创建两个实例类一个是UpdateCompleteJob.cs、UpdateAutoCancelStateJob.cs (之所以创建两个Job是为了能方便大家了解这个组件可以同时执行多个任务)

一:UpdateCompleteJob.cs 代码如下:

namespace JobLibrary
{
    // quartz.net 禁止并发执行DisallowConcurrentExecution是禁止相同JobDetail同时执行,而不是禁止多个不同JobDetail同时执行。建议加上该特性,防止由于任务执行时间太长,长时间占用资源,导致其它任务堵塞。
    [DisallowConcurrentExecution]
    public class UpdateCompleteJob : IJob
    {
        TRA_BargainOrder_Test ExpressModel;
        /// <summary>
        ///在Job 中我们必须实现IJob接口中的Execute 这个方法,才能正确的使用Job
        /// </summary>
        public async Task Execute(IJobExecutionContext context)
        {
            using (var _DbContext = new DefaultDbContext())
            {
                //var tarorder = new TRA_BargainOrder_Test()
                //{
                //    BargainOrderCode="12345688899",
                //    OrderStatus=1
                //};
                //_DbContext.TRA_BargainOrders.Add(tarorder);
                ////保存记录,返回受影响的行数
                //int record = _DbContext.SaveChanges();
                //Console.WriteLine("添加{0}记录成功", record);

                var query = _DbContext.TRA_BargainOrders.Where(c => c.OrderStatus == (int)EnumHelper.OrderStatus.Sended);
                //var query = _DbContext.TRA_BargainOrders.Where(c => c.OrderStatus == (int)EnumHelper.OrderStatus.Sended
                //                                && c.PayStatus == (int)EnumHelper.PayStatus.Paid).OrderBy(c => c.CreateTime).ToList().Take(20);

                foreach (var item in query)
                {
                    if (!string.IsNullOrEmpty(item.ExpressCode))
                    {
                        //根据快递单号获取快递订单信息
                        try
                        {
                            ExpressModel = await _DbContext.TRA_BargainOrders.SingleOrDefaultAsync(s => s.ExpressCode == item.ExpressCode);
                        }
                        catch (Exception e)
                        {
                            new Exception(e.Message);

                        }
   
                        //确定 已签收  修改订单状态 已完成
                        if (ExpressModel.OrderStatus ==1&& ExpressModel.ischeck == 1)
                        {
                            var order = _DbContext.TRA_BargainOrders.FirstOrDefault(c => c.BargainOrderCode == item.BargainOrderCode);
                           // var order = _DbContext.Set<TRA_BargainOrder_Test>().FirstOrDefault(c => c.BargainOrderCode == item.BargainOrderCode);
                            order.OrderStatus = (int)EnumHelper.OrderStatus.Over;
                            order.FlowStatus = (int)EnumHelper.FlowStatus.Over;
                            order.UpdateTime = DateTime.Now;

                            _DbContext.TRA_BargainOrders.Attach(order);
                            _DbContext.Entry(order).State = EntityState.Modified;
                            _DbContext.TRA_BargainOrders.AddOrUpdate(order);
                           
                            
                        }
                        
                    }

                }
                //保存数据库不能放到循环中操作 
                try
                {
                    _DbContext.SaveChanges();
                }

                catch (Exception E)
                { throw new Exception(E.Message); }

            }
        }
    }
}

二:UpdateAutoCancelStateJob.cs 代码如下:

namespace JobLibrary
{
    //在Quartz.Net中,一个job(作业)即为一个类,为了让job能在Quartz.Net的体系中执行,我们必须实现Quartz.Net提供的IJob接口的Execute方法,如本例所实现的IJob接口UpdateAutoCancelStateJob类:
    [DisallowConcurrentExecution]
    public class UpdateAutoCancelStateJob : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            using (var _DbContext = new DefaultDbContext())
            {
  var order = await _DbContext.TRA_BargainOrders.FirstOrDefaultAsync(c => c.OrderStatus == (int)EnumHelper.OrderStatus.UnSend && c.PayStatus == (int)EnumHelper.PayStatus.UnPaid);
                if (order!=null)
                {
                    if (DateDiff(DateTime.Now, order.CreateTime) > 30)
                    {
                        order.OrderStatus = (int)EnumHelper.OrderStatus.Cancel;
                        order.FlowStatus = (int)EnumHelper.FlowStatus.Cancel;
                        order.UpdateTime = DateTime.Now;

                        _DbContext.SaveChanges();
                    }
                }
                
                
            }
        }
    
        //计算时间差的方法
        private int DateDiff(DateTime DateTime1, DateTime DateTime2)
        {

            TimeSpan tss = Convert.ToDateTime(DateTime1) - Convert.ToDateTime(DateTime2);
            int dateDiff = Convert.ToInt32(tss.TotalMinutes);

            return dateDiff;
        }
    }
}

以下是web启动项目下的

三:设置Trigger 触发器,在实际中我是将Trigger和Job 直接注册到 scheduler 调度器中;就是需要将类库生成的DLL 拷贝到你的需要执行的项目的文件中

触发器的JobManage代码如下:

 public class JobManage
    {
        private static ISchedulerFactory sf = new StdSchedulerFactory();

        //调度器
        private static IScheduler scheduler;

        /// <summary>
        /// 读取调度器配置文件的开始时间
        /// </summary>
        //public static void StartScheduleFromConfig()
       public static async void StartScheduleFromConfigAsync()
        {
            string currentDir = AppDomain.CurrentDomain.BaseDirectory;

            try
            {
                XDocument xDoc = XDocument.Load(Path.Combine(currentDir, "JobScheduler.config"));
                var jobScheduler = from x in xDoc.Descendants("JobScheduler") select x;

                var jobs = jobScheduler.Elements("Job");
                XElement jobDetailXElement, triggerXElement;

                //获取调度器
                scheduler = await sf.GetScheduler();

                //声明触发器
                CronTriggerImpl cronTrigger;

                foreach (var job in jobs)
                {
                    //加载程序集joblibaray  
                    Assembly ass = Assembly.LoadFrom(Path.Combine(currentDir, job.Element("DllName").Value));

                    //获取任务名字
                    jobDetailXElement = job.Element("JobDetail");
                    //获取任务触发的时间
                    triggerXElement = job.Element("Trigger");

                    JobDetailImpl jobDetail = new JobDetailImpl(jobDetailXElement.Attribute("job").Value,
                                                            jobDetailXElement.Attribute("group").Value,
                                                            ass.GetType(jobDetailXElement.Attribute("jobtype").Value));


                    if (triggerXElement.Attribute("type").Value.Equals("CronTrigger"))
                    {
                        cronTrigger = new CronTriggerImpl(triggerXElement.Attribute("name").Value,
                                                        triggerXElement.Attribute("group").Value,
                                                        triggerXElement.Attribute("expression").Value);
                        //添加定时器
                        await scheduler.ScheduleJob(jobDetail, cronTrigger);
                    }
                }

                //开始执行定时器
                await scheduler.Start();

            }
            catch (Exception E)
            {
                throw new Exception(E.Message);

            }

        }
        /// <summary>
        /// 关闭定时器
        /// </summary>
        public static void ShutDown()
        {
            if (scheduler != null && !scheduler.IsShutdown)
            {
                scheduler.Shutdown();
            }
        }

        /// <summary>
        /// 从Scheduler 移除当前的Job,修改Trigger   
        /// </summary>
        /// <param name="jobExecution"></param>
        /// <param name="time"></param>
        public static void ModifyJobTime(IJobExecutionContext jobExecution, String time)
        {
            scheduler = jobExecution.Scheduler;
            ITrigger trigger = jobExecution.Trigger;
            IJobDetail jobDetail = jobExecution.JobDetail;
            if (trigger != null)
            {
                CronTriggerImpl ct = (CronTriggerImpl)trigger;
                // 移除当前进程的Job     
                scheduler.DeleteJob(jobDetail.Key);
                // 修改Trigger     
                ct.CronExpressionString = time;
                Console.WriteLine("CronTrigger getName " + ct.JobName);
                // 重新调度jobDetail     
                scheduler.ScheduleJob(jobDetail, ct);
            }
        }

    }

四:配置文件,主要是控制任务执行的时间和Job 的加载 JobScheduler.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!--配置文件,主要是控制任务执行的时间和Job 的加载   
  配置中重要的几个属性 <DllName>JobLibrary.dll</DllName> dll的名字 ;jobtype 属性是dll名字+实例类的名字;expression 这个是设置执行的时间-->
  
    <JobScheduler>
      <Job Description="作业1">
        <DllName>JobLibrary.dll</DllName>
        <JobDetail job="test1" group="test1Group" jobtype="JobLibrary.UpdateCompleteJob" />
        <Trigger name="test1" group="test1Group" type="CronTrigger" expression="0 0/50 * * * ?" />  <!--0 0/10 * * * ? 10分钟--> 
      </Job>
      <Job Description="作业2">
        <DllName>JobLibrary.dll</DllName>
        <JobDetail job="test2" group="test2Group" jobtype="JobLibrary.UpdateAutoCancelStateJob" />
        <Trigger name="test2" group="test2Group" type="CronTrigger" expression="0/10 * * * * ?" /> 
        <!--0/10 * * * * ? 10秒-->  <!-- 每天凌晨1点执行一次:0 0 1 * * ? -->  <!--每天凌晨1点30分执行一次:0 30 1 * * ?--> 
        <!--每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?  -->
        <!-- "0 0/5 14,18 * * ?"    每天14点或18点中,每5分钟触发-->
      </Job>
    </JobScheduler>
  

  <system.web>
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1" />
  </system.web>

</configuration>

五:需要将scheduler 调度器注册到程序中;在程序中Global.asax.cs 中文件中添加注册,在这里启动执行任务

 //需要将scheduler 调度器注册到程序中;在程序中Global.asax.cs 中文件中添加注册,在这里启动执行任务。
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            //执行的任务
            JobManage.StartScheduleFromConfigAsync();
        }
        
        //当网站关闭时结束正在执行的工作
        protected void Application_End(object sender, EventArgs e)
        {
            //   在应用程序关闭时运行的代码
            JobManage.ShutDown();
        }

 六:至此可以启动服务完成定时调度处理任务了

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值