在Quartz中,如何通知作业调度程序正在关闭?

时间:2016-02-02 17:27:14

标签: scheduling quartz.net shutdown

我正在使用Quartz.Net在Windows服务中安排一些长时间运行的作业。我正在尝试优雅地停止服务,例如准备重新启动时。我需要通知作业,以便他们可以根据他们与完成的距离来决定是完成还是中止。我已经看过中断和听众,但我似乎无法弄清楚如何通知挂起的关机。

我也尝试将长期工作分成较小的连续工作,但是当我这样做时,性能会受到严重影响。

2 个答案:

答案 0 :(得分:0)

你提到它,但是你在测试程序关闭时调用了“void Interrupt()”吗?

如果这不起作用,我认为没有内置方式。

但是如果你想探索所有可能性,请获取Quartz.Net的源代码,而不是引用构建的库,将所有(quartz.net).csproj添加到.sln并引用“by project”。 ..并以这种方式逐步完成代码。或者至少查看源代码以收集线索。

然后追逐这个

namespace Quartz.Core
{

    public class QuartzScheduler : MarshalByRefObject, IRemotableQuartzScheduler
    {
    {
        public virtual void Shutdown(bool waitForJobsToComplete)
        {
            if (shuttingDown || closed)
            {
                return;
            }

以下是IInterruptableJob示例。值得一试,看看方法是否开火。您可能已经尝试过此操作,但由于您没有显示该作业的代码,因此这是“其他人做的样本”。

 public class AnInterruptableJob : IJob, IInterruptableJob
    {

        private bool _isInterrupted = false;

        private int MAXIMUM_JOB_RUN_SECONDS = 10;

        /// <summary> 
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {

            /* See http://aziegler71.wordpress.com/2012/04/25/quartz-net-example/ */

            JobKey key = context.JobDetail.Key;

            JobDataMap dataMap = context.JobDetail.JobDataMap;

            int timeOutSeconds = dataMap.GetInt("TimeOutSeconds");
            if (timeOutSeconds <= 0)
            {
                timeOutSeconds = MAXIMUM_JOB_RUN_SECONDS;
            }

            Timer t = new Timer(TimerCallback, context, timeOutSeconds * 1000, 0);

            Console.WriteLine(string.Format("AnInterruptableJob Start : JobKey='{0}', timeOutSeconds='{1}' at '{2}'", key, timeOutSeconds, DateTime.Now.ToLongTimeString()));

            try
            {
                Thread.Sleep(TimeSpan.FromSeconds(7));
            }
            catch (ThreadInterruptedException)
            {
            }

            if (_isInterrupted)
            {
                Console.WriteLine("Interrupted.  Leaving Excecute Method.");
                return;
            }

            Console.WriteLine(string.Format("End AnInterruptableJob (should not see this) : JobKey='{0}', timeOutSeconds='{1}' at '{2}'", key, timeOutSeconds, DateTime.Now.ToLongTimeString()));

        }

        // Timer t = new Timer(TimerCallback, context, 1000, 0);
        private void TimerCallback(Object o)
        {
            IJobExecutionContext context = o as IJobExecutionContext;

            if (null != context)
            {
                context.Scheduler.Interrupt(context.FireInstanceId);
            }
        }

        public void Interrupt()
        {
            _isInterrupted = true;
            Console.WriteLine(string.Format("AnInterruptableJob.Interrupt called at '{0}'", DateTime.Now.ToLongTimeString()));
        }
    }
}

答案 1 :(得分:0)

我不认为作业实例可以自行确定调度程序正在关闭。作业(工作者)线程和服务控制线程之间需要进行一些协调。

这是一个可中断的工作类示例。请注意使用ManualResetEventSlim表示已请求中断,并发出Execute()方法已相应退出的信号。

注意:此代码基于源代码下载附带的Quartz.Server.2010示例项目代码构建。

/// <summary></summary>
[DisallowConcurrentExecution]
public class DumbInterruptableJob : IInterruptableJob, IDisposable
{
    private static readonly ILog logger = LogManager.GetLogger(typeof(DumbInterruptableJob));

    private ManualResetEventSlim _interruptRequestToken;
    private ManualResetEventSlim _interruptCompleteToken;

    /// <summary></summary>
    public DumbInterruptableJob()
    {
        _interruptRequestToken = new ManualResetEventSlim(false);
        _interruptCompleteToken = new ManualResetEventSlim(false);
    }

    /// <summary></summary>
    /// <param name="context"></param>
    public void Execute(IJobExecutionContext context)
    {
        try
        {
            JobKey key = context.JobDetail.Key;

            logger.Info(m => m("Instance {0} of DumbInterruptableJob is working.", key));

            // The work loop
            for (int i = 0; i < 4; i++)
            {
                if (_interruptRequestToken.IsSet)
                {
                    logger.Info(m => m("Work interrupt requested...Exiting."));  // Breakpoint #1
                    return;
                }

                logger.Info(m => m("Work..."));
                Thread.Sleep(2000);
            }

            logger.Info(m => m("Work complete!"));
        }
        catch (Exception ex)
        {
            logger.Error(m => m(ex.Message));
        }
        finally
        {
            _interruptCompleteToken.Set();
        }
    }

    /// <summary></summary>
    public void Interrupt()
    {
        logger.Info(m => m("Setting interrupt flag..."));
        _interruptRequestToken.Set();

        logger.Info(m => m("Waiting for work thread to stop..."));
        _interruptCompleteToken.Wait();
        logger.Info(m => m("Work thread stopped."));  // Breakpoint #2
    }

    /// <summary></summary>
    public void Dispose()
    {
        _interruptCompleteToken.Dispose();
        _interruptRequestToken.Dispose();
    }
}

下一步是在服务停止时中断(取消)所有正在运行的可中断作业。

    public virtual void Stop()
    {
        try
        {
            // Calling Shutdown(false) stops the scheduler from starting new jobs,
            // but the method doesn't block, allowing us to access any running jobs
            // and attempt to cancel (interrupt) them.
            logger.Info(m => m("Shutting down the scheduler..."));
            scheduler.Shutdown(false);

            var interruptableJobs = new List<Task>();

            foreach (var ctx in scheduler.GetCurrentlyExecutingJobs())
            {
                if (ctx.JobInstance is IInterruptableJob)
                {
                    interruptableJobs.Add(Task.Factory.StartNew(() =>
                    {
                        logger.Info(m => m("Waiting for interruptable job {0} to stop...", ctx.JobDetail.Key));
                        scheduler.Interrupt(ctx.JobDetail.Key);
                        logger.Info(m => m("Interruptable job {0} has stopped.", ctx.JobDetail.Key));
                    }));
                }
            }

            if (interruptableJobs.Count > 0)
            {
                logger.Info(m => m("Waiting for all interruptable jobs to stop..."));
                Task.WaitAll(interruptableJobs.ToArray());
                logger.Info(m => m("All interruptable jobs have stopped."));
            }

            logger.Info(m => m("Waiting for all running jobs to complete..."));
            scheduler.Shutdown(true);
            logger.Info(m => m("All running jobs have completed. Scheduler shutdown complete."));  // Breakpoint #3
        }
        catch (Exception ex)
        {
            logger.Error(string.Format("Scheduler stop failed: {0}", ex.Message), ex);
            throw;
        }

        logger.Info("Scheduler shutdown complete");
    }

要查看同步操作,请设置注释中指示的断点,运行它,然后关闭服务(如果从命令行运行,则按Ctrl-C),并观察断点被命中的顺序。