Only running a job between specified times

I have a recurring job that we’d like to run at 3am. If it fails, it runs at 3:10am. This is fine. But if the application fails and is running at 9am it will restart it.

Is there a way of saying “this job can’t start/restart in a particular time period”? At the same time, just to be demanding, I’d like the option of users to manually schedule it.

Not a biggy, Hangfire is excellent. But nice to have…

It sounds like there are two problems:

  1. your Jobs are executing at a time of the day you don’t want them to execute
  2. your Jobs are being retried at a time of the day in which you don’t want them to execute

It’s hard to understand if and why 1) may be happening without understanding how you’ve scheduled your Job. (or maybe I’m missing something because I don’t understand what you mean by “but if the application fails and is running at 9am it will restart it.”)

There are a couple simple ways to control the execution and retry logic for your Job.

  1. You could check the time inside the actual Job and if it’s not what you expect, you could just return instead of continuing execution. Obviously the “job allowed to run window” could come out of config or database or something. You won’t be able to retry the Job from the Hangfire Dashboard later outside of the “job allowed to run window” with this approach, but you could enqueue it manually and pass in a value indicating that you want to override the schedule.

    public void MyJob(bool manuallyOverrideScheduleWindow = false)
    {
    // This is a pretty hacky example, but you can get the idea…
    // Only do work if the manuallyOverrideScheduleWindow is true
    // Or if it’s between 12am and 6am UTC
    if (!manuallyOverrideScheduleWindow || (DateTime.UtcNow.Hour > 6 && DateTime.UtcNow.Hour < 23))
    return;

     // Do work
    

    }

Schedule the Recurring Job like:
RecurringJob.AddOrUpdate<MyClass>("MyJob", c => c.MyJob(), Cron.Daily(3));

Manually trigger the Job from somewhere in your code if you want to override the retry logic:
BackgroundJob.Enqueue<MyClass>(c => c.MyJob(true));

  1. You could use the AutomaticRetryAttribute on your Job with a limit of 0 retries. The nice thing about this approach is that it won’t impact you if you want to manually trigger the Job or re-run a failed Job manually from the Dashboard. The downside is that the Job isn’t going to retry if it fails.

  2. You could write your own JobFilterAttribute and allow it to reschedule failed jobs only if you’re inside your “job allowed to run window”. I don’t have an example of this, but it shouldn’t be too hard to look at the source for AutomaticRetryAttribute and come up with an approach.

Hope this helps!