Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recover from trigger ERROR state after Job constructor threw an exception?

When using Quartz.net to schedule jobs, I occasionally receive an exception when instantiating a job. This, in turn causes Quartz to set the trigger for the job to an error state. When this occurs, the trigger will cease firing until some manual intervention occurs (restarting the service since I'm using in-memory job scheduling).

How can I prevent the error state from being set, or at the very least, tell Quartz to retry triggers that are in the error state?

The reason for the exception is due to flaky network calls that are required to get configuration data that is passed in to the job's constructor. I'm using a custom IJobFactory to do this.

I've seen other references to this without resolutions:

  • https://groups.google.com/forum/#!topic/quartznet/8qaT70jfJPw
  • http://forums.terracotta.org/forums/posts/list/2881.page
like image 805
Brian Vallelunga Avatar asked Aug 28 '15 14:08

Brian Vallelunga


People also ask

What happens if you throw an exception in a constructor?

But there is a more subtle one. If an exception is thrown in a constructor, the object was never fully constructed. This means that its destructor will never be called. Furthermore, there is no way to access an object in an error state. The exception will immediately unwind the local variable.

Is it possible to retry a job trigger?

Unfortunately, in current version, you cannot retry those triggers. As per the documentation of Quartz, It should be extremely rare for this method to throw an exception - basically only the case where there is no way at all to instantiate and prepare the Job for execution.

Why do we need a destructor for exception handling?

Because of the guarantee, this will ensure that each object will have a resource. When the exception is thrown, there is no object. All this is lost when you use an output parameter for the error code. Now the destructor will be called, meaning that it has to deal with all possible error states.

When exception occurs on trigger instatiating IJOB class?

When exception occurs on trigger instatiating IJob class, then trigger change it TRIGGER_STATE to ERROR, and then trigger in this state will no longer fire. To reenable trigger your need to change it state to WAITING, and then it could to fire again.


1 Answers

For the record, I consider this a design flaw of Quartz. If a job can't be constructed once, that doesn't mean it can't always be constructed. This is a transient error and should be treated as such. Stopping all future scheduled jobs violates the principle of least astonishment.

Anyway, my hack solution is to catch any errors that are the result of my job construction and instead of throwing an error or returning null to return a custom IJob instead that simply logs an error. This isn't perfect, but at least it doesn't prevent future triggering of the job.

public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
    try
    {
        var job = this.container.Resolve(bundle.JobDetail.JobType) as IJob;
        return job;
    }
    catch (Exception ex)
    {
        this.logger.Error(ex, "Exception creating job. Giving up and returning a do-nothing logging job.");
        return new LoggingJob(this.logger);
    }
}
like image 96
Brian Vallelunga Avatar answered Nov 08 '22 21:11

Brian Vallelunga