• 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();
            }

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

     
  • 相关阅读:
    SQL Server经典函数之数字去零
    c# 定时执行python脚本
    SQL Server 存储过程生成流水号
    MySQL删除数据表中重复数据
    js封装正则验证
    .NET中将中文符号转换成英文符号
    WebApi中跨域解决办法
    JS生成GUID方法
    LINQ中的连接(join)用法示例
    LINQ分组取出第一条数据
  • 原文地址:https://www.cnblogs.com/Warmsunshine/p/8430451.html
Copyright © 2020-2023  润新知