基于 Quartz.NET 实现可中断的任务

基于 Quartz.NET 实现可中断的任务

Quartz.NET 是一个开源的做业调度框架,很是适合在平时的工做中,定时轮询数据库同步,定时邮件通知,定时处理数据等。 Quartz.NET 容许开发人员根据时间间隔(或天)来调度做业。它实现了做业和触发器的多对多关系,还能把多个做业与不一样的触发器关联。整合了 Quartz.NET 的应用程序能够重用来自不一样事件的做业,还能够为一个事件组合多个做业。 在 Quartz.NET 的默认实现中 Worker 并不是后台线程( IsBackground= false ),因此当咱们终止调度器(调用 Scheduler.Shutdown() 方法)时,假若有一个比较耗时的 Job 正在执行,那么进程将不会当即结束,而是等待这个 Job 执行完毕再结束。html

为了能够当即退出进程,咱们须要了解一个 Quartz.NET 中内置的接口 : IInterruptableJob 。该接口表示一个可中断的任务,实现该接口的 Job 被认为是能够被中断执行的,下面是官方对 IInterruptableJob 接口的定义和解释:数据库

The interface to be implemented by Quartz.IJobs that provide a mechanism for having their execution interrupted. It is NOT a requirement for jobs to implement this interface - in fact, for most people, none of their jobs will. The means of actually interrupting the Job must be implemented within the Quartz.IJob itself (the Quartz.IInterruptableJob.Interrupt method of this interface is simply a means for the scheduler to inform the Quartz.IJob that a request has been made for it to be interrupted). The mechanism that your jobs use to interrupt themselves might vary between implementations. However the principle idea in any implementation should be to have the body of the job's Quartz.IJob.Execute(Quartz.IJobExecutionContext) periodically check some flag to see if an interruption has been requested, and if the flag is set, somehow abort the performance of the rest of the job's work. An example of interrupting a job can be found in the source for the class Example7's DumbInterruptableJob It is legal to use some combination of System.Threading.Monitor.Wait(System.Object) and System.Threading.Monitor.Pulse(System.Object) synchronization within System.Threading.Thread.Interrupt and Quartz.IJob.Execute(Quartz.IJobExecutionContext) in order to have the System.Threading.Thread.Interrupt method block until the Quartz.IJob.Execute(Quartz.IJobExecutionContext) signals that it has noticed the set flag. If the Job performs some form of blocking I/O or similar functions, you may want to consider having the Quartz.IJob.Execute(Quartz.IJobExecutionContext) method store a reference to the calling System.Threading.Thread as a member variable. Then the implementation of this interfaces System.Threading.Thread.Interrupt method can call System.Threading.Thread.Interrupt on that Thread. Before attempting this, make sure that you fully understand what System.Threading.Thread.Interrupt does and doesn't do. Also make sure that you clear the Job's member reference to the Thread when the Execute(..) method exits (preferably in a finally block).

该接口定义了 Interrupt 方法,当调用 Scheduler.Shutdown() 方法时,Quartz.IScheduler 将会调用该方法来中断正在运行的任务。这就意味着,咱们须要本身实现中断方法来中止当前的 Job 。 一般咱们能够经过在任务执行时拿到当前工做的线程,并在中断时调用线程 Abort 方法的方式来终止当前任务。c#

    public class CommonInterruptableJob : IInterruptableJob
    {
        private Thread _currentThread;

        public void Execute(IJobExecutionContext context)
        {
            _currentThread = Thread.CurrentThread;
            try
            {
                //TODO:编写你的任务代码
            }
            finally
            {
                _currentThread = null;
            }
        }

        public void Interrupt()
        {
            if (_currentThread != null)
            {
                _currentThread.Abort();
                _currentThread = null;
            }
        }
    }

这种方法简单粗暴,在一些要求不太严格的状况下表现使人满意。更为优雅的方式是定义布尔型字段 _stop 默认为 false ,在 Interrupt 方法被调用时将其设置为 true 。在 Execute 时不断检测该字段的值,并在合适的时机退出处理。框架

    public class NiceInterruptableJob : IInterruptableJob
    {
        private bool _stop;

        public void Execute(IJobExecutionContext context)
        {
            //假设个人任务是循环 1000 次处理某数据
            for (var i = 0; !_stop && i < 1000; i++)
            {
                //TODO:处理代码
            }
        }

        public void Interrupt()
        {
            _stop = true;
        }
    }

本片文章对 Quartz.NET 进行了一个简单的介绍,且展现了两种不一样的实现任务终止的方式。方式一简单粗暴,编写简单,适合大多数要求不太严格的场合。方式二更加优雅,对退出时机的掌控更加精确,不容易出现危险,但编写更加复杂。ide

相关文章
相关标签/搜索