This sample illustrates the use of Hangfire to send messages from within an NServiceBus endpoint.
Hangfire - An easy way to perform background processing in .NET and .NET Core applications. Hangfire is an open-source framework that helps you to create, process and manage your background jobs.
The approach used in this sample can mitigate some of the architectural drawbacks of the NServiceBus Scheduler. The NServiceBus scheduler is built on top of the Timeout Manager which leverages the queuing system to trigger scheduled actions. Under heavy load there may be some disparity between the expected time of a scheduled action and execution time due to the delay between timeout messages being generated and processed.
Running the project
- Start both the Scheduler and Receiver projects.
- At startup, Scheduler will schedule sending a message to Receiver every minute.
- Receiver will handle the message.
Code Walk-through
Endpoint Helper
This is a helper class used to make the NServiceBus IEndpointInstance
available inside Hangfire jobs. In this sample it is implemented as a static property.
public static class EndpointHelper
{
public static IEndpointInstance Instance { get; set; }
}
Hangfire also supports Dependency Injection (DI) via the JobActivator API for more advanced scenarios.
Configure and start the scheduler
The endpoint is started, and the IEndpointInstance
is stored in the static endpoint helper.
This sample uses in-memory storage for the jobs. Production scenarios should use more robust alternatives: e.g. SqlServer or Redis.
Hangfire calls their scheduler a BackgroundJobServer. It is started automatically when an instance of the BackgroundJobServer
class is instantiated.
var endpointInstance = await Endpoint.Start(endpointConfiguration);
// store the endpointInstance in a static helper class
EndpointHelper.Instance = endpointInstance;
// use in memory storage. Production should use more robust alternatives:
// SqlServer, Redis etc
GlobalConfiguration.Configuration.UseMemoryStorage();
GlobalConfiguration.Configuration.UseColouredConsoleLogProvider();
// create and start scheduler instance
var scheduler = new BackgroundJobServer();
Job definition
This sample passes in an expression pointing to the static Run
method in SendMessageJob
.
public static class SendMessageJob
{
public static Task Run()
{
var endpoint = EndpointHelper.Instance;
return endpoint.Send("Samples.HangfireScheduler.Receiver", new MyMessage());
}
}
Note that the EndpointHelper
is used by the job to get access to the IEndpointInstance
.
Schedule a job
Hangfire will accept any lambda expression as a job definition.
The expression is serialized, stored, and scheduled for execution by the BackgroundJobServer
in Hangfire.
The schedule is set using Cron syntax through the Cron
class. In this sample the job gets scheduled to run every minute.
// Tell Hangfire to schedule the job and trigger every minute
RecurringJob.AddOrUpdate("myJob", () => SendMessageJob.Run(), Cron.Minutely);
Cleanup
The Hangfire server should be disposed when the endpoint is shut down.
scheduler.Dispose();
await endpointInstance.Stop();
The Hangfire scheduler implements the IDisposable
interface. For cleanup purposes, keep a reference to the scheduler instance and call Dispose()
at shutdown. Alternatively, use dependency injection, and let cleanup be automatically be managed.
Scale Out
Note that in this sample, an instance of the Hangfire scheduler is configured to run in every endpoint's instance. If an endpoint is scaled out, then the configured jobs will be executed by each of the running instances. A persistent job storage can help to manage the Hangfire scheduler shared state, including jobs, triggers, calendars, etc.