基於 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

相關文章
相關標籤/搜索