Mediator Pattern with Hangfire

Mediator Pattern with HangfireI’ve run into situations where I need to perform actions requested by the client that may take a bit of time.  The length of time could be variable and I don’t want to have the client waiting for a response.  Let’s take a look at using the Mediator Pattern with Hangfire as a solution to this problem.

In a Web API scenario, the request may come in as a PUT or POST from the client. The API would validate the request, send the task to a queue and then return the client a 202 HTTP status code.

The request has been accepted for processing, but the processing has not been completed. The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place. There is no facility for re-sending a status code from an asynchronous operation such as this.

This way we can handle the work in another process or thread from the initial request.

Hangfire & MediatR

I’ve posted about MediatR before, a nice library that implements the Mediator Pattern for in-process messaging.  I use it for both handling both Commands and Queries.  For our purposes with Hangfire, it will be used for sending requests that are Commands.

I’ve also previously posted about Hangfire, a really great library in .NET for executing background tasks in all types of .NET applications.  If you are interested in Hangfire, take a look at this post first.

Combining these two libraries allows us to take MediatR out of process and use the same implementation we are used to using in-process.

Helper

Hangfire provides the ability for your task to be a method on a class.

However, the above will not work as there is an issue with serializing the Command.

The issue appears to be with MediatR’s Send<Unit> method.  Trying to serialize the expression when it contains a type parameter may be the issue.  If you are aware of what this specific issue is, please let know in the comments.

Since we are using commands that have no return type I just created a static helper function.

SetSerializerSettings

Also, in order for serialization to be correct we must set the Json.NET TypeNameHandling setting.

Setting to include type information when serializing JSON and read type information so that the create types are created when deserializing JSON.

Example

So let’s put this simple example all together.

I’m putting the Hangfire server where I’m also creating the task (client).  Because of this, I’m printing out which thread is sending the task, as well as which thread the task is executed on.  If you were running multiple Hangfire server instances, this would happen on any one of them and allows you to distribute tasks.

The resulting output displays that the task was sent from Thread 8 and was executed on Thread 18.

Mediator Pattern with Hangfire

 

Comments

Let me know if you are using MediatR or the Mediator Pattern with Hangfire and how you have implemented it.  Please share in the comments below or on twitter.

Related Posts

Here are some other posts that relate to Hangfire or MediatR that I have written.

Background Tasks in .NET

Background Tasks in .NETIt seems like every application I’ve ever written, at some point needs to run a task in the background that is to be scheduled at some point in the future.

My need for tasks as reoccurring batch jobs has decreased significantly over the years because of my applications being more event driven.

Nowadays, I will often use Event Stores Persistent Subscriptions with my event stream as a queue.  However, I’m not event sourcing all parts of the application and not always using Event Store.

If you have any questions, please follow me on Twitter.

Hangfire

I stumbled upon Hangfire a couple years ago when trying to find solution to running background tasks in a .NET console application running as a service with Topshelf.

When I was trying to find a solution, I need to have tasks distributed across multiple worker services.  Hangfire has this problem solved.

An easy way to perform fire-and-forget, delayed and recurring tasks inside ASP.NET applications. No Windows Service required.

Backed by persistent storages. Open and free for commercial use.

Background method calls and their arguments are serialized and may overcome the process boundaries.

You can use Hangfire on different machines to get more processing power with no configuration – synchronization is performed automatically.

Getting Started

The docs are really good over at the Hangfire site, so I don’t want to rewrite what is already over there.  I do however just want to give you enough to show you how simple it is to use and let you decide if its a viable solution for you.

There are two ways in which you can get started.  If you plan on using Hangfire within an ASP.NET Web Application and want to use SQL Server as your storage mechanism, then you can install the boostrapper package which has everything you need.

Install-Package HangFire -Version 1.5.6

If you plan on using in any other project type (Windows Service, Console, OWIN-Compatible Web Application, Azure Worker Role) or different storage mechanism, you can install the Hangfire.Core.

Install-Package HangFire.Core -Version 1.5.6

Configuration

Configuration is the same if you are in an ASP.NET Web Application or any other project type.  What differs is where you put this configuration.

But it is incredibly straight forward.  You simply use the GlobalConfiguration class to configure the entry point.

Server

The server is what processes the background tasks we will define later.  In order to create a server, you simply create a BackgroundJobServer.  This can be called from any project you wish to act as a Hangfire server.  As with configuration, where you place create the BackgroundJobServerwill depend on the project type.

Create Background Task

There are different types of background tasks that we can now create from any other project type.  These calls do not need to be made from the same application as the server.

  • Fire-and-forget
  • Delay
  • Recurring

Any type of Tasks can be called from any client and it will be executed on a Hangfire server.

Fire-and-forget

You simply call the Enqueue with your action you want to invoke on the server.

The Enqueue method does not call the target method immediately, it runs the following steps instead:

  1. Serialize a method information and all its arguments.
  2. Create a new background job based on the serialized information.
  3. Save background job to a persistent storage.
  4. Enqueue background job to its queue.

For my example, I’m going to Enqueue a new task in the same application as my server.

When you run this application, here is the console output.

Hangfire

Delay & Reoccurring

You can also create tasks that are delayed from the time of creation.  This may be useful for possibly invoking a method to send to a user a couple days after they have signed up for a trial of your software.

You can also create reoccurring tasks and supports CRON expressions.

Data Storage

There are fair amount of stable different storage providers such as Redis, SQL Server, SQL Azure, Mongo, PostgreSql.   Be sure to check out each of the data providers github/website to make sure they are still active and production ready as it seems a few may be out of date or experimental.

I highly recommend you check out this project if you are looking for this type of functionality.

Comments

I’d love to hear how you handle running background tasks. Are you using some other tool?  Please share in the comments below or on twitter.

Related Posts

Validating Commands with the Decorator Pattern

Validating CommandsThis post is how I have manged to handle validating commands and queries and belongs to a series about different aspects of applying CQRS

Although these examples are demonstrating usage in commands, they are aslo applicable to queries.

Examples are using using MediatR to handle our requests.

If you are unfamiliar with CQRS or MediatR, here are some other relevant posts:

Feature

First let’s take a look at our feature for Changing a Customers Pricing Level.  In this example I’ve organized all aspects of this feature into one file.  This single file contains our NancyFX Module and Route, Command and Command Handler.

Validation

One small piece of validation I would like to add, is validating the CustomerId is not an empty Guid.

When deserialization occurs thru the Bind() method, if the CustomerId is not present in the payload, the CustomerId will be an empty Guid (00000000-0000-0000-0000-000000000000).

The simplest approach is to add the validation to our Handler.

This doesn’t look incredibly horrible, however we are violating SRP and as you develop more complex commands, validating them will start to consume your Handler.

Decorator Pattern

In object-oriented programming, the decorator pattern (also known as Wrapper, an alternative naming shared with the Adapter pattern) is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.[1] The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.[2]

The decorator pattern is pretty straight forward, and even if you never knew the term, you likely already used it.

Here is our decorator for wrapping the command handler with our new validation handler.

Validation Handler

Now we can extract our validation logic out of our command handler and add it to a validation handler which will be invoked prior to the command handler.

Invoking

The one piece of the puzzle that I can’t show exactly in this example will be dependent on what container you use.  When you create a new instance of MediatR you provide a single and multi instance factory in the constructor.  Generally this will be your preferred container.   Check out our container docs to see how you register a decorator.

Comments

I’d love to hear how you handle command or query validation.  Please share in the comments below or on twitter.


Related Posts