C# Quartz 整理
因项目需要,在C#中使用了定时程序。自然就使用了Quartz了
但是使用的时候,经过一段时间后,发现了两个重大问题,结果导致的是一样的,就是都导致了定时不会继续执行了。
第一个问题是,定时程序发布在IIS下,但是IIS自己本身是有回收机制的,然后如果到了晚上,没人操作后台了,那么IIS会自动回收定时程序。
这里可以通过代码层面解决,就是说让IIS一直处于被使用状态,自然就不会回收了。
具体的代码改动是:
在项目中的Global.asax文件里,增加一段
protected void Application_End(object sender, EventArgs e) { // 在应用程序关闭时运行的代码 //解决应用池回收问题 System.Threading.Thread.Sleep(5000); string strUrl = ProjectPara.ProPath; System.Net.HttpWebRequest _HttpWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(strUrl); System.Net.HttpWebResponse _HttpWebResponse = (System.Net.HttpWebResponse)_HttpWebRequest.GetResponse(); System.IO.Stream _Stream = _HttpWebResponse.GetResponseStream();//得到回写的字节流 }
这个的方法触发的节点是应用程序关闭的时候会执行此方法,目的是通过HttpWebRequest发送一次请求,然后得到返回的字节流,这样每次应用程序关闭了,都会请求一次,就很好的阻止了IIS的回收。
还有一个问题是,定时程序执行中,如果程序中抛异常了,那么也会导致定时失效,原因是出现了异常,在代码中有处理,如果出现异常,直接停掉定时任务
public virtual void Execute(IJobExecutionContext context) { ValidationErrors validationErrors = new ValidationErrors(); //取状态值 JobDataMap dataMap = context.JobDetail.JobDataMap; string id = dataMap.GetString(ID);//任务ID string taskName = dataMap.GetString(TASKNAME);//任务名称 // JobKey jobKey = context.JobDetail.Key; string jobName = jobKey.Name;//任务名称=任务名称+任务ID try { //开始执行业务逻辑 Log.Write(jobName, "开始任务>>>>>>" + jobName, "成功"); //取当前程序集 Assembly assem = Assembly.GetExecutingAssembly(); //创建任务对象并执行 Object o = assem.CreateInstance(taskName, false, BindingFlags.ExactBinding, null, new Object[] { }, null, null); MethodInfo m = assem.GetType(taskName).GetMethod("RunJob");//默认调用方法 Object ret = m.Invoke(o, new Object[] { dataMap, jobName, id, taskName }); //更新任务状态 TaskJob.UpdateState(ref validationErrors, jobName, 1, ret.ToString()); ////////////////////////////////////////////////////////////////// if (validationErrors.Count > 0) { Log.Write(jobName, "Error", validationErrors.Error); } Log.Write(jobName, "<<<<<<<结束任务" + jobName, "成功"); } catch (System.Exception e) { Log.Write(jobName, "Exception", e.Message); JobExecutionException e2 = new JobExecutionException(e); e2.UnscheduleAllTriggers = true; throw e2; } }
但是并不是所有情况都需要出现异常了,就停掉trigger,可以继续执行下次,所以注视掉这句即可。
这里引申一个问题,因为定时是invoke调用的,这个方法会忽略掉内部方法的catch,直接在当前invoke中捕获。
所以这里处理下即可。