Hangfire.Community.Outbox
1.0.0
See the version list below for details.
dotnet add package Hangfire.Community.Outbox --version 1.0.0
NuGet\Install-Package Hangfire.Community.Outbox -Version 1.0.0
<PackageReference Include="Hangfire.Community.Outbox" Version="1.0.0" />
paket add Hangfire.Community.Outbox --version 1.0.0
#r "nuget: Hangfire.Community.Outbox, 1.0.0"
// Install Hangfire.Community.Outbox as a Cake Addin #addin nuget:?package=Hangfire.Community.Outbox&version=1.0.0 // Install Hangfire.Community.Outbox as a Cake Tool #tool nuget:?package=Hangfire.Community.Outbox&version=1.0.0
Hangfire.Outbox
Outbox pattern implementation for Hangfire using EntityFramework Core
1. Motivation
Basically, the need to enqueue a Hangfire job as part of an EntityFramework unit of work...
IMPORTANT: If your DbContext's connection is the same as Hangfire's (ie: both use the same SQL Server db), you can probably enqueue a job as part of the same ambient transaction as your application's code and you probably don't need this project.
Sometimes, as part of a business process, we need to persist data to multiple stores as part of a transaction but oftentimes a distributed transaction is impossible. The outbox pattern allows saving the information as part of a single ACID database transaction and process further messages asynchronously garanteeing an at least once delivery of messages to other systems (ie: service bus, emails, other databases, stc.).
However, if your Hangfire's store is not RDMBS or your store's database is not the same as your application's database, you would need a distributed transaction which is not currently supported. This is where this project comes in handy as it allows saving the jobs as outbox messages in your application's DbContext!
A classic example of the outbox pattern usage is sending an email as part of a business process. Let's say we want to send an email to a customer as part of an order processing method, we would normally save some changes to our database and use Hangfire to schedule an email to the customer. Most of the time, this works fine. However, if the transaction that persists the application's state fails and/or rolls back, Hangfire would still send the email as its enqueuing was not persisted as part of the same transaction. The project allows enqueuing job as outbox messages ensuring they will only be enqueued if the application's transaction succeeds.
For a great explanation of what the outbox pattern is and what it tries to solve, please read these excellent blog posts from Derek Comartin and Milan Jovanović:
Outbox Pattern: Reliably Save State & Publish Events
Outbox Pattern For Reliable Microservices Messaging
2. Requirements
- Hangfire 1.8 or above
- .net 6 project with EntityFramework Core 6
- .net 7 project with EntityFramework Core 7
- .net 8 project with EntityFramework Core 8
3. Installation
dotnet add package Hangfire.Community.Outbox
4. Setup
Program.cs
In your program setup, register Hangfire Outbox by passing your application DbContext as a generic argument:
builder.Services.AddHangfireOutbox<AppDbContext>();
Then add this line:
app.UseHangfireOutbox();
DbContext.OnModelCreating
If you haven't already, override the OnModelCreating function of your DbContext and add the following call:
modelBuilder.MapOutboxJobs();
ie:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.MapOutboxJobs();
base.OnModelCreating(modelBuilder);
}
This will map an entity that will persist jobs to be started at a later time as part of the EntityFramework unit of work.
EntityFramework migration
Create a migration to create the outbox table in your database:
dotnet ef migrations add AddOutboxTable
Update your database to apply the pending migration(s):
dotnet ef database update
You're now setup and ready to use the outbox pattern to queue your Hangfire jobs!
5. Usage
Whenever you want to queue or schedule a job as part of an EntityFramework unit of work, just use one of the following approach using the same syntax as you would when queuing directly with Hangfire:
Using extension methods on the DbContext instance
dbContext.EnqueueOutbox(() => Console.WriteLine("Hello from hangfire!"));
Using extension methods on the IBackgroundJobClient instance
backgroundJobClient.EnqueueOutbox(() => Console.WriteLine("Hello from hangfire!"), dbContext);
Make sure to save changes on your DbContext to persist the outbox job:
await dbContext.SaveChangesAsync();
The Hangfire job will only be enqueued or scheduled when the changes are persisted to the database or an enclosing transaction completes.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Hangfire.Core (>= 1.8.0)
- Microsoft.EntityFrameworkCore (>= 6.0.0)
- Microsoft.EntityFrameworkCore.Abstractions (>= 6.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 6.0.0)
- Microsoft.Extensions.Hosting (>= 6.0.0)
-
net7.0
- Hangfire.Core (>= 1.8.0)
- Microsoft.EntityFrameworkCore (>= 7.0.0)
- Microsoft.EntityFrameworkCore.Abstractions (>= 7.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 7.0.0)
- Microsoft.Extensions.Hosting (>= 7.0.0)
-
net8.0
- Hangfire.Core (>= 1.8.0)
- Microsoft.EntityFrameworkCore (>= 8.0.0)
- Microsoft.EntityFrameworkCore.Abstractions (>= 8.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.0)
- Microsoft.Extensions.Hosting (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.