在所有Quartz .NET IInterruptableJob上触发中断

我正在使用Quartz调度程序,并尝试在关闭应用程序时关闭所有作业。 我有一个专业工作,做“保持”或“忙碌等待”,基本上直到它得到一个条件,它坐在那里耐心等待。

由于新的集成点,这项工作是新的。 该应用程序使用Topshelf作为服务运行,每当我们尝试关闭服务以升级它时,现在该作业正在运行,我们必须最终重新启动服务器以使其关闭。

无论如何,这里很奇怪,我有一个单一的jobtype,当我尝试使用作业FireInstanceIdJobKey在下面的代码段中触发中断时:

 _logger.InfoFormat("{0} scheduler interrupting listener", scheduler.SchedulerName); scheduler.Interrupt(ListenerKeys.Realtime); _logger.InfoFormat("{0} scheduler shutting down", scheduler.SchedulerName); scheduler.Shutdown(true); _logger.InfoFormat("{0} scheduler shut down", scheduler.SchedulerName); 

我得到一个例外:

Job’Listeners.Realtime’不能被中断,因为它没有实现Quartz.IInterruptableJob

人们会认为这是直截了当的。 但是,这是使用此作业键的唯一作业:

 ListenerJob : BaseJob, IInterruptableJob { // some other code referenced in ExecuteJob public void Interrupt() { _dequeuer.StopDequeing(); } } 

我会说你是如何实现它的,所以我的问题变成了:Quartz中是否存在已知错误? 是否存在组密钥和中断的问题? 有没有办法告诉调度程序中断所有可中断的作业? 还有其他选择吗?

UPDATE

我决定从以下答案运行以下代码以获得更多诊断。 var接口确实包含IInterruptableJob

 var jobs = scheduler.GetCurrentlyExecutingJobs().Where(x => Equals(x.JobDetail.Key, ListenerKeys.Realtime)); var job1 = jobs.First(); var interfaces = job1.JobDetail.JobType.GetInterfaces(); 

另外,我按照下面的建议运行了ReportInterruptableJob,它检查了程序集并确认了ListenerJob实现了接口。

UPDATE2:

好吧,我去了git hub,并运行了确切的meshos。 作为IInterruptableInterface的Job.JobInstance返回null,这就是我得到错误的原因。 我不明白我想,我是如何在IJo周围形成JobInstance实现IInterruptableJob

UPDATE3:好的….所以我在引导程序中找到了一些使用JobWrapper 的东西。 我对此一无所知,但我确信这是其中的一部分。

所以我同意另一个答案(C Knight)可能会关闭JobKey。

如果你已经实现了界面……并且你有正确的JobKey ..那么你不应该得到那个例外。

以下是我打断工作的代码。 我也试图找到“找到钥匙”的逻辑。

  private static void InterruptAJob(JobKey foundJobKey, IScheduler sched) { if (null != foundJobKey) { sched.Interrupt(foundJobKey); } } 

附加

这是我找到工作密钥的代码。

我会从它开始……….放一些断点……看看你的JobKey是否在集合中。 也许修改例程(在你找出魔法位置之后)按照一定的标准找到一个工作密钥……如果找不到你期望找到的东西,就抛出exception。 Aka,不要“假设”JobKey存在…..但是查询它并抛出相应的exception(或者如果没有找到匹配则写入相应的== null逻辑)……. vs“假设它必须在那里“接近。

同样,下面是“入门”代码…….我的概念validation只有一个工作,所以我没有具体。

 private static JobKey FindaJobKey(IScheduler sched, ILogger logger) { JobKey returnJobKey = null; IList jobGroupNames = sched.GetJobGroupNames(); if (null != jobGroupNames) { if (jobGroupNames.Count > 0) { GroupMatcher groupMatcher = GroupMatcher.GroupEquals(jobGroupNames.FirstOrDefault()); Quartz.Collection.ISet keys = sched.GetJobKeys(groupMatcher); returnJobKey = keys.FirstOrDefault(); if (null == returnJobKey) { throw new ArgumentOutOfRangeException("No JobKey Found"); } } } Thread.Sleep(TimeSpan.FromSeconds(1)); return returnJobKey; } 

附加:

也许是这样的:

 private static JobKey FindJobKey(IScheduler sched, ILogger logger, string jobGroupName) { JobKey returnJobKey = null; IList jobGroupNames = sched.GetJobGroupNames(); if (null != jobGroupNames) { string matchingJobGroupName = jobGroupNames.Where(s => s.Equals(jobGroupName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); if (null != matchingJobGroupName) { GroupMatcher groupMatcher = GroupMatcher.GroupEquals(matchingJobGroupName); Quartz.Collection.ISet keys = sched.GetJobKeys(groupMatcher); if (null != keys) { if (keys.Count > 0) { throw new ArgumentOutOfRangeException(string.Format("More than one JobKey Found. (JobGroupName='{0}')", jobGroupName)); } returnJobKey = keys.FirstOrDefault(); if (null != returnJobKey) { throw new ArgumentOutOfRangeException(string.Format("No JobKey Found. (JobGroupName='{0}')", jobGroupName)); } } } } Thread.Sleep(TimeSpan.FromSeconds(1)); return returnJobKey; } 

另一个快速而肮脏的“看看你发生了什么”的方法。

  private static void ShowJobs(IScheduler sched) { Console.WriteLine(""); Console.WriteLine("ShowJobs : Start"); GroupMatcher matcherAll = GroupMatcher.AnyGroup(); Quartz.Collection.ISet jobKeys = sched.GetJobKeys(matcherAll); foreach (JobKey jk in jobKeys) { Console.WriteLine(string.Format("{0} : {1}", jk.Group, jk.Name)); } Console.WriteLine("ShowJobs : End"); Console.WriteLine(""); } 

附加:

也许以另一种方式来到它。 我略微调整了一种方法。 但又添了一个新的。 ReportIInterruptableJobs

查看ReportIInterruptableJobs报告的内容。

  private static void ShowJobs(IScheduler sched, ILogger logger) { Console.WriteLine(""); Console.WriteLine("ShowJobs : Start"); GroupMatcher matcherAll = GroupMatcher.AnyGroup(); Quartz.Collection.ISet jobKeys = sched.GetJobKeys(matcherAll); foreach (JobKey jk in jobKeys) { Console.WriteLine(string.Format("{0} : {1}", jk.Group, jk.Name)); IJobDetail jobData = sched.GetJobDetail(jk); if (null != jobData) { Console.WriteLine(string.Format("{0}", jobData.JobType.AssemblyQualifiedName)); } } Console.WriteLine("ShowJobs : End"); Console.WriteLine(""); } private static void ReportIInterruptableJobs() { Type typ = typeof(IInterruptableJob); ICollection types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => typ.IsAssignableFrom(p)).ToList(); if (null != types) { foreach (Type t in types) { Console.WriteLine(string.Format("{0}", t.AssemblyQualifiedName)); } } } 

你100%肯定你的ListenerJobJobKey实际上是Listeners.Realtime ? 是否会有一个使用JobKey的不同工作? 在您调用Interrupt()时, Listeners.Realtime会被更新为不同的值吗? Quartz绝对找到了JobKey的工作,因为如果Quartz根本找不到工作, JobKey不会抛出exception。 它找到的工作没有实现IInterruptableJob。 我会通过在ListenerJobExecute(IJobExecutionContext context)方法中设置断点并检查context.JobDetail.Key仔细检查ListenerJobJobKey值。 我的钱在JobKey上与众不同。 此外,查看BaseJob的代码可能对我们有所帮助。