We are leaving Russia. We are against aggression and war with Ukraine. It is a tragedy for our nations, it is a nightmare

HangFire 0.9 released – say hello to recurring jobs!

HangFire 0.9 released with recurring jobs feature! Here is the short list of changes.

  • Added – Out-of-the-box support for running recurring jobs.
  • AddedSqlServerStorage now also accepts connection string names.
  • ChangedIBackgroundJobClient does not implement the IDisposable interface anymore.
  • ChangedIMonitoringApi does not implement the IDisposable interface anymore.
  • Changed – Improve DateTime resolution for job arguments by including milliseconds.
  • Changed – Removed deprecated RetryAttribute class. Please, use AutomaticRetryAttribute.
  • FixedKeyNotFoundException when accessing job cancellation token with Redis.
  • Fixed – Theoretical race condition that makes HangFire Server invisible from Monitor.

Please see the blog post for some more information.

And let me demonstrate how it is easy to run recurring tasks now:

RecurringJob.AddOrUpdate(() => Console.Write("Easy!"), Cron.Daily);

That’s all and nothing more!

Hi Sergey, first of all thank you for building this awesome looking library!

I am currently using http://www.quartz-scheduler.net on a project at work, but one of the things that it lacks is a really nice user interface so that you can see how well your jobs are performing! So when I came across Hangfire.io I got pretty excited :slight_smile:

This project looks like it does lots of the stuff that quartz does. So I am keen to ask you a few questions if that is okay?

  1. If a recurring job is scheduled to run once a minute, but accidentally takes longer than that will Hangfire only allow 1 instance of that job to run? I ask this because Quartz has an attribute called DisallowConcurrentExecution – It is an attribute that can be added to the Job class that tells Quartz not to execute multiple instances of a given job definition.

  2. Do you have a way to limit the number of workers that a particular job can use so that it doesn’t starve the pool of available workers? I have some jobs that take longer to run than others and it is possible that these jobs use up all the available workers and the other jobs don’t get a chance to fire on time. So it would be cool if you could say for this job type only run a max of 5 workers for it.

I probably will have other questions but I realise that I should just grab the code at work tomorrow and start playing around!


Hello, @superlogical, thanks for you interest!

But before I start to answer the questions, let me tell you about the differences between Quartz.NET and HangFire. You already know that Quartz.NET is built around scheduler and its main purpose to handle recurring tasks.

HangFire is built entirely for fire-and-forget tasks, and leverages message queues to handle them (but they are persistent comparing to CLR ThreadPool). You can have thousands of messages (queued background work items), and a couple of workers on one or several machines that fetch and process background jobs. So, it is incorrect to talk about worker pool starvation from the queue size point of view – this is the way how HangFire works, message by message, job by job.

  1. HangFire has the same attribute, but with different name – DisableConcurrentExecution, you can apply it to the calling method. But be aware of worker pool contention, when all workers waits for the job’s completion. In this case you should start the separate HangFire Server instance with different name for these jobs.
  2. Recurring job scheduler neither perform the work itself, nor tell a concrete worker to perform it. It only creates a new background job and places it on a queue, and worker thread will fetch it sooner or later (depending on queue size). If the overall latency is very high to you, you can use additional HangFire Server instances. If you want some of your jobs to be performed sooner than the others, consider using multiple queues – you can tell HangFire Server instance what queues it should process.

I’m writing the user guide at the moment, so feel free to ask the questions!