【问题标题】:Handle JobExecutionException in Quartz.net在 Quartz.net 中处理 JobExecutionException
【发布时间】:2010-07-14 12:54:32
【问题描述】:

可能是一个愚蠢的问题...但无论如何...

我已经设置了quartz,可以安排作业,我可以确认作业(实现IJob接口)正在工作。

查看网站上的文档,(教程第 3 课):

您可以从执行方法中抛出的唯一异常类型是JobExecutionException

我希望当我没有明确处理的异常发生时,它应该抛出一个 JobExecutionException,以便我可以将它记录到“父”应用程序中。我已经将我的代码包装在一个 try catch 中,并抛出了 JobExecutionException,但现在在哪里处理呢?

我不会在任何地方调用 execute 方法,它由 Quartz 处理(在单独的线程上)。那么,当它发生时我该如何处理该错误。我真的不想吞下作业中的错误

【问题讨论】:

  • 好的,做了更多的研究,看起来 JobListener 就是我要找的。现在弄清楚它将如何处理异常。
  • annnnnd.... 不走运。即使有监听器,应用程序在抛出异常时也会崩溃。帮助!
  • @tardomatic-如果您有一个连接到作业/组名称的作业侦听器,无论作业成功还是失败,都会调用该侦听器。在您抛出 JobExecutionException(基于您检测到错误)后,Quartz 将认为作业未完成(根据定义,Quartz 认为作业完成除非您触发 JobExecutionException)。现在,当您在侦听器的 JobWasExecuted() 方法中时,您可以检查 JobExecutionException 参数以查看它是否已设置。现在您知道作业是否失败,并且您可以选择在将来再次执行作业之前执行清理等任务。

标签: c# exception-handling quartz.net


【解决方案1】:

我通过使用基类捕获所有异常解决了这个问题:

public abstract class JobBase : IJob
{
    protected JobBase()
    {
    }

    public abstract void ExecuteJob(JobExecutionContext context);

    public void Execute(JobExecutionContext context)
    {
        string logSource = context.JobDetail.FullName;

        try
        {
            ExecuteJob(context);
        }
        catch (Exception e)
        {
           // Log exception
        }
    }
}

你的 Job 类应该是这样的:

public class SomeJob : JobBase
{
    public SomeJob()
    {
    }

    public override void ExecuteJob(JobExecutionContext context)
    {
        // Do the actual job here
    }
}

【讨论】:

  • 很好的解决方案,可以在其他不同的石英作业中启用通用日志记录。谢谢!
  • ...你不能是认真的... gna catch 'em all 不应该是最佳实践...最好添加一个监听器并对有异常的工作结束做出反应......
  • 我不确定我是否遵循您的思路,想举个例子吗? (pastebin 代码的链接将是完美的)
  • 刚刚说我已经为这个问题实现了几乎完全相同的解决方案。对于任何想知道@AndreasNiedermair 的评论的人 - 有一个包罗万象的做法可能是正确的,但你不需要这样做。作业应该处理它们的异常,但是如果您有未捕获的异常,使用此解决方案比简单地允许底层异常进一步传播更可取,因为这至少可以让您以“石英方式”处理问题稍后。
  • @TomFromThePool 我同意你的观点,不需要坚持任何做法。但是,将异常处理分离给侦听器要方便得多(例如,您可以一般地这样做......)。
【解决方案2】:

通常您会按如下方式设置作业的执行方法:

try
{
    // the work you want to do goes here
}
catch (ExceptionTypeYouWantToHandle1 ex1)
{
    // handle exception
}
catch (ExceptionTypeYouWantToHandle2 ex2)
{
    // handle exception
}
// and so on
catch (Exception ex)
{
    // something really unexpected happened, so give up
    throw new JobExecutionException("Something awful happened", ex, false); // or set to true if you want to refire
}

此时,调度程序本身会将异常记录到它正在记录的任何位置(基于配置)。

【讨论】:

  • 我已经很久没有使用这个了,我没有可用的代码来测试它是否有效。值得怀疑的是,抛出 JobExecutionException 是问题所在。我把它扔了,但 Quartz 并没有像你提到的那样处理它并记录它,它只是作为一个未处理的异常一直冒泡。
  • ...你不能是认真的... gna catch 'em all 不应该是最佳实践...最好添加一个监听器并对有异常的工作结束做出反应......
  • 最佳实践是让您的工作处理自己的异常。您是否建议为每种作业类型创建一个单独的侦听器来处理异常?
  • 我遇到了类似的问题。你知道什么对 Quartz 社区来说很有价值吗?一个 youtube 视频系列 + 一个石英忍者的代码示例,使用 jobStore、单元测试和一些调试来设置完整(简单)的石英实现,您故意导致并发现许多常见的“gothchas”。
  • @jvilalta 当您知道哪条 line 可能会引发异常时,为什么不在那里捕获呢?是的,那将完全正确-而不是开头的try和方法结尾的catch-但是.net强制这样做的方式与java不同,所以全局异常处理程序-我做到了不是说全局catch - 很常见(就像您在控制台应用程序中使用AppDomainUnhandledException-handler 一样),并且“最好”和最可重用的版本是监听器正是这个任务。
【解决方案3】:

如前所述,在全局级别“检测”JobExecutionException 的正确方法是实现并注册一个 IJobListener 并检查 JobWasExecuted() 方法中的 JobExecutionException 参数是否为 != null。

但是,我遇到的问题(从 OP 的附加评论来看,他也遇到了这个问题)是 Quartz 没有处理 JobExecutionException(因为它应该),这导致了一个未处理的异常杀死了应用程序。

到目前为止,我使用的是 Quartz.NET 2.0.1 版本 (.NET3.5) 包中的预编译 DLL。为了解决问题,我引用了 Quartz 项目/源代码,令我惊讶的是它突然工作了?!

有趣的是,这是执行 IJob 并处理 JobExecutionException 的 Quartz 库代码

try {
    if (log.IsDebugEnabled) {
       log.Debug("Calling Execute on job " + jobDetail.Key);
    }
    job.Execute(jec);
    endTime = SystemTime.UtcNow();
} catch (JobExecutionException jee) {
    endTime = SystemTime.UtcNow();
    jobExEx = jee;
    log.Info(string.Format(CultureInfo.InvariantCulture, "Job {0} threw a JobExecutionException: ", jobDetail.Key), jobExEx);
} catch (Exception e) {
   // other stuff here...
}

接下来的事情是直接引用我新编译的 DLL,这也很有效。可悲的是,我无法告诉您为什么这样做有效,而且我目前没有时间进一步研究它,但也许这对某人有所帮助。也许其他人可以证实这一点,甚至做出解释。可能跟不同的目标平台(x86/64bit)有关?

【讨论】:

  • 这是不正确的。捕捉(JobExecutionException jee){ endTime = SystemTime.UtcNow(); jobExEx = 吉;捕获并处理 JobExcecutionException.. 我没有看到抛出,因此,它在这一点被处理并且它不会被抛出导致未处理的异常。然后将异常分配给 jobExEx 并发送给侦听器。我质疑让一个侦听器处理所有作业的异常,甚至每个作业只有一个侦听器来处理异常是否合理。所有作业都应该知道如何处理自己的异常。
  • @jvilalta:可能有误会。引用的代码是来自 Quartz.NET 库的实际代码。不是来自应用程序的代码。我只是想指出 Quartz 如何在内部处理 JobExecutionException。
  • 这是哪个文件?代码,这个类或文件的名称是什么?
  • @NikhilVandanapu:它来自 \src\Quartz\Core\JobRunShell.cs
  • @Rev1.0 谢谢。如果我想捕获与 Sql Server 和石英相关的异常,你能告诉我这是否是我应该阅读的文件。在我的用例中,如果 Sql Server 关闭,我应该收到通知,石英使用的是关闭。
猜你喜欢
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 2011-02-28
  • 1970-01-01
  • 2013-03-01
  • 2017-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多