Stefan Holm Olsen

4 tips and tricks for Hangfire on Optimizely CMS

On several of the sites, I have worked on, there was a need for an advanced job scheduling and job queuing component. I often tend to install and use Hangfire for this purpose, simply because it is more customizable than the Optimizely CMS scheduled job framework.

Installing Hangfire on Optimizely has already been a subject on many blog posts. So, I will spare you this part.

Instead, I will show you four helpful tricks I came up with over the years.

  1. Redirect internal logging to the Optimizely logger
  2. Correlate related telemetry in Application Insights
  3. Capture the Content Language
  4. Only run Hangfire on scheduler app instance

1. Redirect internal logging to the Optimizely logger

Inside a Hangfire job, I usually inject an ILogger<T> instance through the constructor for use in my job code. This way I can log whatever I want, and the log entries will be delivered wherever the site is configured to deliver. This is fine.

But Hangfire also writes its own internal log entries, just not to any of the default log providers in an Optimizely site. To connect the two dots, I always add these two classes to my projects.

This is basically a mapper class that acquires a logger class from the Optimizely logging framework (which in turn acquires a more specific logger class). To apply this log provider, call UseLogProvider in your Hangfire configuration block (see last chapter).

If a site is connected to Azure Application Insights, it is already correlating all telemetry (logging, dependencies and exceptions) to a parent request. This is very useful for debugging and monitoring the site.

A Hangfire job is not a request, so telemetry from it will not automatically be correlated. Luckily this can easily be arranged with this single class.

3. Capture the Content Language

When a job is queued from a web request, to be processed separately from the request, it would be nice if we could load content in the same language as the web request.

Luckily, I once came up with a job filter that captures the content language when adding the job to the queue. Just before running the job, it changes the content language of the job thread. This way I do not need to specify the content language to IContentLoader. It is simply inferred from the current thread.

4. Only run Hangfire on scheduler app instance

If a site is run in a multi-server configuration with a separate scheduler app instance (in Optimizely DXP or on your own), all built-in scheduled jobs will only run on that app instance. The idea behind this is that performing such jobs will not affect the visitor experience with slower performance.

If the Optimizely scheduling service runs only on the scheduler app instance, then the same should apply to Hangfire. Luckily, I also have a way to do that. See the initialization module below.

Initializing the Hangfire extensions

My four extensions all need to be registered or added to Hangfire to be used. There are two places to do this.

In Startup.cs:

In an initializable module (let's call it HangfireInitialization):