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

 六:至此可以啟動服務完成定時調度處理任務了

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM