Hangfire Best Practice: Invoke by ID

Hangfire Best PracticeIn my previous post, I created a few extension methods for Hangfire and MediatR in order to enqueue an IRequest. However, it was not following Hangfire Best Practice.

The purpose was to have the IRequest serialized entirely when calling Enqueue(), which would be stored in Hangfires storage.

Then when the request would be invoked, Hangfire would deserialize the IRequest and call Mediators Send().

My functioning example worked as expected. However, Hangfire recommends making your job arguments small and simple.

Best Practice

Method invocation (i.e. a job) is serialized during the background job creation process. Arguments are converted into JSON strings using the TypeConverter class. If you have complex entities and/or large objects; including arrays, it is better to place them into a database, and then pass only their identities to the background job.

Instead of doing this:

public void Method(Entity entity) { }

Consider doing this:

public void Method(int entityId) { }

Darren Cauthon also recommend this approach when I first started looking at integrating Hangfire and MediatR.

New Process

I liked my initial approach using extension methods and using the Hangfire’s JobActivator in order to construct the class that will be sending the Request to MediatR.

Using the best practice the changes needed would be:

  • Pass a database connection factory to the Hangfire Configuration extension method (UseMediatr)
  • Create a new MediatR extension method to pass a CommandId and the Request
    • Insert a new record into a database with the CommandId and serialized Request
  • Create a new method that will be invoked by Hangfire when only using the Command
    • Select the record out of the database and deserialize the Request
    • Send to MediatR

Hangfire Configuration

A database connection factory needs to be passed when configuration MediatR with Hangfire.

Enqueue

Now in Enqueue a new command with or without a Command Id.

Database

In my working code, I’m creating a table [MediatR.Request] in the Hangfire database automatically which is used to store the serialized commands.

Since this is a example, it only contains the CommandId and the serialized command.  However, it would likely make send to store the date created as well as when the date the command was invoked and completed by Hangfire.

Demo

GitHubI’ve published all the Extension methods as well as a demo containing two console applications.  One console application is the producer which enqueues commands, while the consumer handles them.

You can find all the source on GitHub

https://github.com/dcomartin/Hangfire.MediatR.Demo

Comments

Let me know if you are using MediatR along with Hangfire.  Please share in the comments below or on twitter.

  • Paul Wheeler

    I ended up using this approach by default because Hangfire replaced a home grown background processing engine that was using times and a database table. All I had to do to switch was start queuing up the Ids in Hangfire and turn off the other process’s timer. So I guess that is a kind of advantage, Hangfire becomes just an implementation detail and can be easily replaced later if need be. BTW: Hangfire has been working flawlessly with Redis for months now, I pretty much keep forgetting it’s there 🙂

    • Great to hear about Redis! Likely going to be switching to it sooner rather than later as well.