Skip to content

Latest commit

History

458 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Hangfire.Mongo

BuildNuGet downloadsLicense

A MongoDB storage provider for Hangfire. Use MongoDB-compatible servers (including Azure Cosmos DB configured with the MongoDB API, and AWS DocumentDB) to persist and process Hangfire jobs.

Why Hangfire.Mongo?

  • Reliable job storage and state management in MongoDB.
  • Multiple queue notification strategies (change streams, tailable collections, polling).
  • Schema migration and backup strategies with configurable behavior.
  • Extension points to customize collection creation, serialization and UTC handling.
  • Works with ASP.NET Core and console-hosted Hangfire servers.

Prerequisites

  • .NET Standard / .NET Core compatible runtime used by your application.
  • MongoDB server (community, Atlas, or other compatible servers). For Cosmos DB use the MongoDB API endpoint.

Hangfire (project and docs)

Installation

Install from NuGet (recommended):

dotnet add package Hangfire.Mongo

Or via the Package Manager Console in Visual Studio:

PM> Install-Package Hangfire.Mongo

Quick start — ASP.NET Core

Add Hangfire and Hangfire.Mongo in your Startup/Program configuration:

// Program.cs or Startup.csvarmongoUrl=newMongoUrl("mongodb://localhost:27017/jobs");varmongoClient=newMongoClient(mongoUrl.ToMongoUrl());services.AddHangfire(configuration =>configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseMongoStorage(mongoClient,mongoUrl.DatabaseName,newMongoStorageOptions{Prefix="hangfire.mongo",CheckConnection=true,MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}}));services.AddHangfireServer();

Quick start — Console

varoptions=newMongoStorageOptions{MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newDropMongoMigrationStrategy(),BackupStrategy=newNoneMongoBackupStrategy()}};usingvarstorage=newMongoStorage(MongoClientSettings.FromConnectionString("mongodb://localhost:27017"),"jobs",options);usingvarserver=newBackgroundJobServer(storage);

Configuration highlights

  • Prefix: prefix for Hangfire collection names (default: no prefix).
  • CheckConnection: verify connectivity at startup (recommended for production).
  • InvisibilityTimeout: controls how long a job remains in Processing before becoming visible again; configure to avoid stuck jobs.
  • CheckQueuedJobsStrategy: choose between Watch (change streams), Poll, or TailNotificationsCollection.

Cosmos DB (MongoDB API) — Getting started

Hangfire.Mongo works with Azure Cosmos DB only when the Cosmos account is configured to use the MongoDB API. The SQL API is not compatible with the MongoDB driver and therefore not supported.

Important: this project includes a specialized options type, CosmosStorageOptions (in Hangfire.Mongo.CosmosDB), which adjusts a number of settings that are required or recommended for Cosmos DB. Use CosmosStorageOptions instead of MongoStorageOptions when targeting Cosmos DB.

Key overrides in CosmosStorageOptions

  • CheckQueuedJobsStrategy = Poll
    • Cosmos DB does not reliably support change streams or tailable capped collections in the same way as a regular MongoDB server; polling is the safe strategy.
  • CheckConnection = false
    • Cosmos DB's connection semantics and the way it handles metadata can make the generic startup connection check unsuitable; the Cosmos-specific options disable the default connection ping.
  • SupportsCappedCollection = false
    • Cosmos DB (Mongo API) does not support capped collections — tailing a notifications collection is not available.
  • MigrationLockTimeout = 2 minutes
    • Increased timeout to accommodate Cosmos DB's operational latencies.
  • Factory = new CosmosFactory()
    • A Cosmos-specific factory is used to create storage components tuned for Cosmos behavior.
  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • The UTC date/time strategy is tuned for Cosmos' server responses; this replaces the default set of strategies.

⚠️Note on testing and support

Because access to Azure Cosmos DB (MongoDB API) is limited in the project's test environment, the Cosmos-specific configuration and code paths are not as exhaustively tested as the standard MongoDB implementation. If you use Cosmos DB and encounter issues, please open an issue or submit a PR — community feedback and contributions are appreciated and will help improve compatibility. I will rely on community help to identify and fix provider-specific bugs that cannot be validated in the project's CI/test environment.

Example — recommended Cosmos setup

usingHangfire.Mongo.CosmosDB;varmongoUrl=newMongoUrl("mongodb://<user>:<password>@<your-account>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb");varclient=newMongoClient(mongoUrl.ToMongoUrl());varoptions=newCosmosStorageOptions{// CosmosStorageOptions already sets recommended defaults for Cosmos// You can still tweak other options here if necessary (timeouts, prefix, migration options...)Prefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core pattern: use the Hangfire configuration lambda and call the Cosmos-specific// extension method `UseCosmosStorage` provided in `CosmosBootstrapperConfigurationExtensions`.// This registers the storage with Hangfire and returns the created `CosmosStorage` instance.services.AddHangfire(cfg =>cfg.UseCosmosStorage(client,"<database>",options));services.AddHangfireServer();
// Non-ASP.NET Core / GlobalConfiguration pattern:usingHangfire;usingHangfire.Mongo.CosmosDB;// Register Cosmos storage on the global Hangfire configuration and capture the returned storagevarstorage=GlobalConfiguration.Configuration.UseCosmosStorage(client,"<database>",options);// Create a server that uses the registered storageusingvarserver=newBackgroundJobServer(storage);

Notes:

  • The UseCosmosStorage extension method lives in the Hangfire.Mongo.CosmosDB namespace; add using Hangfire.Mongo.CosmosDB; to access it.
  • The extension wraps construction of CosmosStorage, registers it on the Hangfire global configuration, and returns the created storage instance so you can use it directly when creating a BackgroundJobServer if needed.

Implications and guidance

  • Do not rely on change-stream based notifications or tailable collections with Cosmos — the Poll strategy is used by default in CosmosStorageOptions.
  • CheckConnection is disabled by default for Cosmos; if you enable it you'll need Cosmos-specific checks and longer timeouts (not recommended).
  • Because SupportsCappedCollection is false, TailNotificationsCollection is not a valid CheckQueuedJobsStrategy for Cosmos.
  • CosmosFactory is used to wire Cosmos-specific implementations (e.g., connections, write semantics); if you need to customize behavior, consider subclassing CosmosFactory rather than the base MongoFactory.
  • UTC date/time handling for Cosmos is tuned via IsMasterUtcDateTimeStrategy — if you replace it, ensure any custom strategy matches Cosmos' server response behavior.

DocumentDB (AWS DocumentDB / Mongo-compatible)

This repository provides a DocumentDbStorage path for Mongo-compatible DocumentDB servers (for example AWS DocumentDB). This is intended for MongoDB-compatible services that restrict certain admin commands or have slightly different server responses compared to a full MongoDB server.

⚠️Note on testing and support

DocumentDB-compatible providers (such as AWS DocumentDB) are similarly less well-tested in this project due to limited access to those managed services during development. The DocumentDbStorageOptions and DocumentDB-specific code paths have been designed to be conservative, but if you find bugs or provider-specific issues please report them or contribute fixes — community help is essential for robust support. I will rely on community contributions and reports to discover and resolve provider-specific issues that cannot be exercised in the project's automated tests.

Use DocumentDbStorageOptions (in Hangfire.Mongo.DocumentDB) when targeting DocumentDB-compatible services. The DocumentDbStorageOptions constructor narrows the UTC date/time strategies to use IsMasterUtcDateTimeStrategy, because unprivileged users on these services may not be able to run higher-privileged commands used by other strategies.

Key points about DocumentDbStorageOptions

  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • Restricts date/time probing to the isMaster command which is generally available to unprivileged users on DocumentDB implementations.
  • Other storage options retain the defaults from MongoStorageOptions unless you override them.

How to use

usingHangfire.Mongo.DocumentDB;varclient=newMongoClient("mongodb://<user>:<password>@<your-docdb-host>:27017/?ssl=true");varoptions=newDocumentDbStorageOptions{// You can still customize prefix, migration options, and other MongoStorageOptions membersPrefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core patternservices.AddHangfire(cfg =>cfg.UseDocumentDbStorage(client,"<database>",options));services.AddHangfireServer();// Non-ASP.NET Core / GlobalConfiguration patternvarstorage=GlobalConfiguration.Configuration.UseDocumentDbStorage(client,"<database>",options);usingvarserver=newBackgroundJobServer(storage);

Notes and guidance

  • UseDocumentDbStorage is implemented in DocumentDbBootstrapperConfigurationExtensions (namespace Hangfire.Mongo.DocumentDB). Add using Hangfire.Mongo.DocumentDB; to access it.
  • DocumentDB-compatible services may require TLS/SSL and specific MongoDB driver settings; ensure MongoClientSettings are tuned for your provider (timeouts, retry policy, TLS settings).
  • Because DocumentDbStorageOptions narrows UTC probing to isMaster, it is safer to run with unprivileged users. If you need a different strategy, provide a custom UtcDateTimeStrategy but test carefully against your provider.
  • If your provider exposes additional incompatibilities (capped collections, change streams, etc.), adjust MongoStorageOptions flags (for example SupportsCappedCollection) or use CheckQueuedJobsStrategy = CheckQueuedJobsStrategy.Poll when change-streams/tailable collections are not available.
  • If you need provider-specific creation/wiring logic, consider subclassing the provided DocumentDbStorage or CosmosFactory/MongoFactory patterns as appropriate.

Extending the library

The project provides well-known extension points for advanced customization. Two common extension points are MongoFactory and the UTC date/time strategies.

Note: most classes and methods in this library are public and many are virtual (for example MongoFactory, MongoWriteOnlyTransaction, MongoConnection and related components). This design allows you to subclass and override behaviour at many points — you can swap internal components, change commit behavior, alter notification logic, or plug-in custom serialization by overriding the appropriate virtual methods.

In short: almost all methods are public and many are virtual, so you can change almost any behaviour by subclassing and overriding the provided components.

  1. Overriding MongoFactory

MongoFactory is the place where MongoDB collections, indexes and other components are created. By providing a custom implementation you can:

  • Create custom indexes or collection options,
  • Plug-in custom DTO serialization or mapping,
  • Swap collection implementations for testing.

Accurate examples (based on the real MongoFactory API):

// Example 1: override the database context creation to enforce a custom prefixpublicclassCustomMongoFactory:MongoFactory{publicoverrideHangfireDbContextCreateDbContext(IMongoClientmongoClient,stringdatabaseName,stringprefix){// Force a different prefix for all Hangfire collectionsvarenforcedPrefix="myapp.hangfire";returnbase.CreateDbContext(mongoClient,databaseName,enforcedPrefix);}}
// Example 2: override the distributed lock creation to change resource naming (or add instrumentation)publicclassCustomMongoFactoryWithLocks:MongoFactory{publicoverrideMongoDistributedLockCreateMongoDistributedLock(stringresource,TimeSpantimeout,HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){// Use an application-specific prefix for the lock resource namevarcustomResource=$"MyAppLock:{resource}";// You could also wrap the returned lock with your own implementation that adds logging/metricsreturnnewMongoDistributedLock(customResource,timeout,dbContext,storageOptions);}}

Wiring a custom factory

  • MongoStorageOptions exposes a Factory property. Assign your custom factory before creating MongoStorage or before calling UseMongoStorage:
varoptions=newMongoStorageOptions{Factory=newCustomMongoFactory(),};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

If you need to customize other behaviors (job fetching, notifications, expiration manager etc.), inspect the available virtual methods on MongoFactory and override the appropriate creation method (for example CreateMongoJobFetcher, CreateMongoNotificationObserver, CreateMongoExpirationManager).

  1. Custom UTC date/time strategies

Date/time serialization is important for cross-platform correctness and compatibility with various MongoDB servers. The library exposes swappable UTC strategies (look for implementations under UtcDateTime or similar namespaces) so you can control how DateTime values are serialized and deserialized.

Example custom strategy:

publicclassCustomUtcDateTimeStrategy:UtcDateTimeStrategy{publicoverrideBsonValueSerialize(DateTimedateTime){// Force DateTime to UTC and store as BsonDateTimereturnnewBsonDateTime(DateTime.SpecifyKind(dateTime,DateTimeKind.Utc));}publicoverrideDateTimeDeserialize(BsonValuevalue){returnvalue.AsBsonDateTime.ToUniversalTime();}}

Wiring the strategy

  • Set MongoStorageOptions.UtcDateTimeStrategies to an array of the strategies you want to use (in order of preference). This property is an array of UtcDateTimeStrategy instances and should be configured before creating MongoStorage / calling UseMongoStorage.

Example:

varoptions=newMongoStorageOptions{UtcDateTimeStrategies=newUtcDateTimeStrategy[]{newCustomUtcDateTimeStrategy(),newAggregationUtcDateTimeStrategy(),newServerStatusUtcDateTimeStrategy()}};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));
  • Alternative: if you need lower-level control (for example registering Bson serializers or setting up class maps) you can wire the strategy inside a custom MongoFactory implementation — the factory is invoked when the storage constructs its internal components, so it can be used to ensure serializers and mappings are registered before collections are used.

Example — customize MongoWriteOnlyTransaction

A deeper extension point is MongoWriteOnlyTransaction. You can subclass it to alter commit behavior, add retries, instrumentation or change how notifications are signalled. Below is a compact example that:

  • Subclasses MongoWriteOnlyTransaction and overrides ExecuteCommit to add a retry loop,
  • Supplies the custom transaction from a custom MongoFactory, and
  • Wires the factory via MongoStorageOptions.Factory.
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;usingMongoDB.Bson;usingMongoDB.Driver;usingHangfire.Mongo.Database;// 1) Custom transaction with a simple retry around the bulk commitpublicclassCustomMongoWriteOnlyTransaction:MongoWriteOnlyTransaction{publicCustomMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions):base(dbContext,storageOptions){}protectedoverridevoidExecuteCommit(IMongoCollection<BsonDocument>jobGraph,List<WriteModel<BsonDocument>>writeModels,BulkWriteOptionsbulkWriteOptions){constintmaxAttempts=3;intattempt=0;while(true){try{// use base behavior for actual bulk writebase.ExecuteCommit(jobGraph,writeModels,bulkWriteOptions);return;}catch(MongoException)when(++attempt<maxAttempts){// simple backoff; replace with your preferred retry policy or instrumentationThread.Sleep(200*attempt);}}}}// 2) Custom factory that returns the custom transactionpublicclassCustomMongoFactory:MongoFactory{publicoverrideMongoWriteOnlyTransactionCreateMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){returnnewCustomMongoWriteOnlyTransaction(dbContext,storageOptions);}}// 3) Wiring via optionsvaroptions=newMongoStorageOptions{Factory=newCustomMongoFactory()};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

Notes

  • You can override other virtual methods on MongoWriteOnlyTransaction (for example SignalJobsAddedToQueues or Log) to change notifications or debug output.
  • Use a custom factory when you need to swap multiple internal components; override several Create... methods as needed.

Migration and backups

The library supports migration strategies to handle schema changes between releases. Choose the strategy that fits your operational needs:

  • Throw (default): refuse to start when a schema version mismatch is detected.
  • Drop: drop Hangfire collections and recreate schema from scratch (data loss).
  • Migrate: attempt to migrate data forward. May not preserve all data — test carefully.

Backup strategies

  • None: do not perform backups before migration.
  • Collection clone: copy collections within the database before applying migrations.
  • Custom: implement MongoBackupStrategy to provide a bespoke backup mechanism (e.g., export to files or another database).

Example configuration snippet:

varmigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()};varstorageOptions=newMongoStorageOptions{MigrationOptions=migrationOptions,InvisibilityTimeout=TimeSpan.FromMinutes(30)};GlobalConfiguration.Configuration.UseMongoStorage("<connection string with database name>",storageOptions);

Naming conventions

Hangfire.Mongo enforces PascalCase for its internal collections and will ignore application-wide convention packs (such as CamelCaseElementNameConvention) for Hangfire collections. This ensures schema stability across applications using different conventions.

Features summary

  • Durable job and state storage in MongoDB.
  • Multiple queue notification strategies: change streams (Watch), polling (Poll), and tailable notifications (TailNotificationsCollection).
  • Schema migration and configurable backup strategies.
  • Pluggable MongoFactory for customizing collections, indexes and serializers.
  • Swappable UTC date/time strategies for fine-grained date handling.
  • Configurable collection prefixing and connection checks.
  • Compatible with MongoDB and MongoDB-compatible services (including Cosmos DB using the MongoDB API).

Contributing

Contributions are welcome. When submitting changes:

  • Add tests for new behavior (if applicable).
  • Document breaking changes and migration steps.
  • Include migration/backup code when modifying schema.

Contributors

License

Hangfire.Mongo is released under the MIT License. See the LICENSE file for details.

About

Mongo DB support for Hangfire

Resources

Stars

281 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - gottscj/Hangfire.Mongo: Mongo DB support for Hangfire · GitHub
Skip to content

Latest commit

History

458 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Hangfire.Mongo

BuildNuGet downloadsLicense

A MongoDB storage provider for Hangfire. Use MongoDB-compatible servers (including Azure Cosmos DB configured with the MongoDB API, and AWS DocumentDB) to persist and process Hangfire jobs.

Why Hangfire.Mongo?

  • Reliable job storage and state management in MongoDB.
  • Multiple queue notification strategies (change streams, tailable collections, polling).
  • Schema migration and backup strategies with configurable behavior.
  • Extension points to customize collection creation, serialization and UTC handling.
  • Works with ASP.NET Core and console-hosted Hangfire servers.

Prerequisites

  • .NET Standard / .NET Core compatible runtime used by your application.
  • MongoDB server (community, Atlas, or other compatible servers). For Cosmos DB use the MongoDB API endpoint.

Hangfire (project and docs)

Installation

Install from NuGet (recommended):

dotnet add package Hangfire.Mongo

Or via the Package Manager Console in Visual Studio:

PM> Install-Package Hangfire.Mongo

Quick start — ASP.NET Core

Add Hangfire and Hangfire.Mongo in your Startup/Program configuration:

// Program.cs or Startup.csvarmongoUrl=newMongoUrl("mongodb://localhost:27017/jobs");varmongoClient=newMongoClient(mongoUrl.ToMongoUrl());services.AddHangfire(configuration =>configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseMongoStorage(mongoClient,mongoUrl.DatabaseName,newMongoStorageOptions{Prefix="hangfire.mongo",CheckConnection=true,MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}}));services.AddHangfireServer();

Quick start — Console

varoptions=newMongoStorageOptions{MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newDropMongoMigrationStrategy(),BackupStrategy=newNoneMongoBackupStrategy()}};usingvarstorage=newMongoStorage(MongoClientSettings.FromConnectionString("mongodb://localhost:27017"),"jobs",options);usingvarserver=newBackgroundJobServer(storage);

Configuration highlights

  • Prefix: prefix for Hangfire collection names (default: no prefix).
  • CheckConnection: verify connectivity at startup (recommended for production).
  • InvisibilityTimeout: controls how long a job remains in Processing before becoming visible again; configure to avoid stuck jobs.
  • CheckQueuedJobsStrategy: choose between Watch (change streams), Poll, or TailNotificationsCollection.

Cosmos DB (MongoDB API) — Getting started

Hangfire.Mongo works with Azure Cosmos DB only when the Cosmos account is configured to use the MongoDB API. The SQL API is not compatible with the MongoDB driver and therefore not supported.

Important: this project includes a specialized options type, CosmosStorageOptions (in Hangfire.Mongo.CosmosDB), which adjusts a number of settings that are required or recommended for Cosmos DB. Use CosmosStorageOptions instead of MongoStorageOptions when targeting Cosmos DB.

Key overrides in CosmosStorageOptions

  • CheckQueuedJobsStrategy = Poll
    • Cosmos DB does not reliably support change streams or tailable capped collections in the same way as a regular MongoDB server; polling is the safe strategy.
  • CheckConnection = false
    • Cosmos DB's connection semantics and the way it handles metadata can make the generic startup connection check unsuitable; the Cosmos-specific options disable the default connection ping.
  • SupportsCappedCollection = false
    • Cosmos DB (Mongo API) does not support capped collections — tailing a notifications collection is not available.
  • MigrationLockTimeout = 2 minutes
    • Increased timeout to accommodate Cosmos DB's operational latencies.
  • Factory = new CosmosFactory()
    • A Cosmos-specific factory is used to create storage components tuned for Cosmos behavior.
  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • The UTC date/time strategy is tuned for Cosmos' server responses; this replaces the default set of strategies.

⚠️Note on testing and support

Because access to Azure Cosmos DB (MongoDB API) is limited in the project's test environment, the Cosmos-specific configuration and code paths are not as exhaustively tested as the standard MongoDB implementation. If you use Cosmos DB and encounter issues, please open an issue or submit a PR — community feedback and contributions are appreciated and will help improve compatibility. I will rely on community help to identify and fix provider-specific bugs that cannot be validated in the project's CI/test environment.

Example — recommended Cosmos setup

usingHangfire.Mongo.CosmosDB;varmongoUrl=newMongoUrl("mongodb://<user>:<password>@<your-account>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb");varclient=newMongoClient(mongoUrl.ToMongoUrl());varoptions=newCosmosStorageOptions{// CosmosStorageOptions already sets recommended defaults for Cosmos// You can still tweak other options here if necessary (timeouts, prefix, migration options...)Prefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core pattern: use the Hangfire configuration lambda and call the Cosmos-specific// extension method `UseCosmosStorage` provided in `CosmosBootstrapperConfigurationExtensions`.// This registers the storage with Hangfire and returns the created `CosmosStorage` instance.services.AddHangfire(cfg =>cfg.UseCosmosStorage(client,"<database>",options));services.AddHangfireServer();
// Non-ASP.NET Core / GlobalConfiguration pattern:usingHangfire;usingHangfire.Mongo.CosmosDB;// Register Cosmos storage on the global Hangfire configuration and capture the returned storagevarstorage=GlobalConfiguration.Configuration.UseCosmosStorage(client,"<database>",options);// Create a server that uses the registered storageusingvarserver=newBackgroundJobServer(storage);

Notes:

  • The UseCosmosStorage extension method lives in the Hangfire.Mongo.CosmosDB namespace; add using Hangfire.Mongo.CosmosDB; to access it.
  • The extension wraps construction of CosmosStorage, registers it on the Hangfire global configuration, and returns the created storage instance so you can use it directly when creating a BackgroundJobServer if needed.

Implications and guidance

  • Do not rely on change-stream based notifications or tailable collections with Cosmos — the Poll strategy is used by default in CosmosStorageOptions.
  • CheckConnection is disabled by default for Cosmos; if you enable it you'll need Cosmos-specific checks and longer timeouts (not recommended).
  • Because SupportsCappedCollection is false, TailNotificationsCollection is not a valid CheckQueuedJobsStrategy for Cosmos.
  • CosmosFactory is used to wire Cosmos-specific implementations (e.g., connections, write semantics); if you need to customize behavior, consider subclassing CosmosFactory rather than the base MongoFactory.
  • UTC date/time handling for Cosmos is tuned via IsMasterUtcDateTimeStrategy — if you replace it, ensure any custom strategy matches Cosmos' server response behavior.

DocumentDB (AWS DocumentDB / Mongo-compatible)

This repository provides a DocumentDbStorage path for Mongo-compatible DocumentDB servers (for example AWS DocumentDB). This is intended for MongoDB-compatible services that restrict certain admin commands or have slightly different server responses compared to a full MongoDB server.

⚠️Note on testing and support

DocumentDB-compatible providers (such as AWS DocumentDB) are similarly less well-tested in this project due to limited access to those managed services during development. The DocumentDbStorageOptions and DocumentDB-specific code paths have been designed to be conservative, but if you find bugs or provider-specific issues please report them or contribute fixes — community help is essential for robust support. I will rely on community contributions and reports to discover and resolve provider-specific issues that cannot be exercised in the project's automated tests.

Use DocumentDbStorageOptions (in Hangfire.Mongo.DocumentDB) when targeting DocumentDB-compatible services. The DocumentDbStorageOptions constructor narrows the UTC date/time strategies to use IsMasterUtcDateTimeStrategy, because unprivileged users on these services may not be able to run higher-privileged commands used by other strategies.

Key points about DocumentDbStorageOptions

  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • Restricts date/time probing to the isMaster command which is generally available to unprivileged users on DocumentDB implementations.
  • Other storage options retain the defaults from MongoStorageOptions unless you override them.

How to use

usingHangfire.Mongo.DocumentDB;varclient=newMongoClient("mongodb://<user>:<password>@<your-docdb-host>:27017/?ssl=true");varoptions=newDocumentDbStorageOptions{// You can still customize prefix, migration options, and other MongoStorageOptions membersPrefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core patternservices.AddHangfire(cfg =>cfg.UseDocumentDbStorage(client,"<database>",options));services.AddHangfireServer();// Non-ASP.NET Core / GlobalConfiguration patternvarstorage=GlobalConfiguration.Configuration.UseDocumentDbStorage(client,"<database>",options);usingvarserver=newBackgroundJobServer(storage);

Notes and guidance

  • UseDocumentDbStorage is implemented in DocumentDbBootstrapperConfigurationExtensions (namespace Hangfire.Mongo.DocumentDB). Add using Hangfire.Mongo.DocumentDB; to access it.
  • DocumentDB-compatible services may require TLS/SSL and specific MongoDB driver settings; ensure MongoClientSettings are tuned for your provider (timeouts, retry policy, TLS settings).
  • Because DocumentDbStorageOptions narrows UTC probing to isMaster, it is safer to run with unprivileged users. If you need a different strategy, provide a custom UtcDateTimeStrategy but test carefully against your provider.
  • If your provider exposes additional incompatibilities (capped collections, change streams, etc.), adjust MongoStorageOptions flags (for example SupportsCappedCollection) or use CheckQueuedJobsStrategy = CheckQueuedJobsStrategy.Poll when change-streams/tailable collections are not available.
  • If you need provider-specific creation/wiring logic, consider subclassing the provided DocumentDbStorage or CosmosFactory/MongoFactory patterns as appropriate.

Extending the library

The project provides well-known extension points for advanced customization. Two common extension points are MongoFactory and the UTC date/time strategies.

Note: most classes and methods in this library are public and many are virtual (for example MongoFactory, MongoWriteOnlyTransaction, MongoConnection and related components). This design allows you to subclass and override behaviour at many points — you can swap internal components, change commit behavior, alter notification logic, or plug-in custom serialization by overriding the appropriate virtual methods.

In short: almost all methods are public and many are virtual, so you can change almost any behaviour by subclassing and overriding the provided components.

  1. Overriding MongoFactory

MongoFactory is the place where MongoDB collections, indexes and other components are created. By providing a custom implementation you can:

  • Create custom indexes or collection options,
  • Plug-in custom DTO serialization or mapping,
  • Swap collection implementations for testing.

Accurate examples (based on the real MongoFactory API):

// Example 1: override the database context creation to enforce a custom prefixpublicclassCustomMongoFactory:MongoFactory{publicoverrideHangfireDbContextCreateDbContext(IMongoClientmongoClient,stringdatabaseName,stringprefix){// Force a different prefix for all Hangfire collectionsvarenforcedPrefix="myapp.hangfire";returnbase.CreateDbContext(mongoClient,databaseName,enforcedPrefix);}}
// Example 2: override the distributed lock creation to change resource naming (or add instrumentation)publicclassCustomMongoFactoryWithLocks:MongoFactory{publicoverrideMongoDistributedLockCreateMongoDistributedLock(stringresource,TimeSpantimeout,HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){// Use an application-specific prefix for the lock resource namevarcustomResource=$"MyAppLock:{resource}";// You could also wrap the returned lock with your own implementation that adds logging/metricsreturnnewMongoDistributedLock(customResource,timeout,dbContext,storageOptions);}}

Wiring a custom factory

  • MongoStorageOptions exposes a Factory property. Assign your custom factory before creating MongoStorage or before calling UseMongoStorage:
varoptions=newMongoStorageOptions{Factory=newCustomMongoFactory(),};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

If you need to customize other behaviors (job fetching, notifications, expiration manager etc.), inspect the available virtual methods on MongoFactory and override the appropriate creation method (for example CreateMongoJobFetcher, CreateMongoNotificationObserver, CreateMongoExpirationManager).

  1. Custom UTC date/time strategies

Date/time serialization is important for cross-platform correctness and compatibility with various MongoDB servers. The library exposes swappable UTC strategies (look for implementations under UtcDateTime or similar namespaces) so you can control how DateTime values are serialized and deserialized.

Example custom strategy:

publicclassCustomUtcDateTimeStrategy:UtcDateTimeStrategy{publicoverrideBsonValueSerialize(DateTimedateTime){// Force DateTime to UTC and store as BsonDateTimereturnnewBsonDateTime(DateTime.SpecifyKind(dateTime,DateTimeKind.Utc));}publicoverrideDateTimeDeserialize(BsonValuevalue){returnvalue.AsBsonDateTime.ToUniversalTime();}}

Wiring the strategy

  • Set MongoStorageOptions.UtcDateTimeStrategies to an array of the strategies you want to use (in order of preference). This property is an array of UtcDateTimeStrategy instances and should be configured before creating MongoStorage / calling UseMongoStorage.

Example:

varoptions=newMongoStorageOptions{UtcDateTimeStrategies=newUtcDateTimeStrategy[]{newCustomUtcDateTimeStrategy(),newAggregationUtcDateTimeStrategy(),newServerStatusUtcDateTimeStrategy()}};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));
  • Alternative: if you need lower-level control (for example registering Bson serializers or setting up class maps) you can wire the strategy inside a custom MongoFactory implementation — the factory is invoked when the storage constructs its internal components, so it can be used to ensure serializers and mappings are registered before collections are used.

Example — customize MongoWriteOnlyTransaction

A deeper extension point is MongoWriteOnlyTransaction. You can subclass it to alter commit behavior, add retries, instrumentation or change how notifications are signalled. Below is a compact example that:

  • Subclasses MongoWriteOnlyTransaction and overrides ExecuteCommit to add a retry loop,
  • Supplies the custom transaction from a custom MongoFactory, and
  • Wires the factory via MongoStorageOptions.Factory.
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;usingMongoDB.Bson;usingMongoDB.Driver;usingHangfire.Mongo.Database;// 1) Custom transaction with a simple retry around the bulk commitpublicclassCustomMongoWriteOnlyTransaction:MongoWriteOnlyTransaction{publicCustomMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions):base(dbContext,storageOptions){}protectedoverridevoidExecuteCommit(IMongoCollection<BsonDocument>jobGraph,List<WriteModel<BsonDocument>>writeModels,BulkWriteOptionsbulkWriteOptions){constintmaxAttempts=3;intattempt=0;while(true){try{// use base behavior for actual bulk writebase.ExecuteCommit(jobGraph,writeModels,bulkWriteOptions);return;}catch(MongoException)when(++attempt<maxAttempts){// simple backoff; replace with your preferred retry policy or instrumentationThread.Sleep(200*attempt);}}}}// 2) Custom factory that returns the custom transactionpublicclassCustomMongoFactory:MongoFactory{publicoverrideMongoWriteOnlyTransactionCreateMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){returnnewCustomMongoWriteOnlyTransaction(dbContext,storageOptions);}}// 3) Wiring via optionsvaroptions=newMongoStorageOptions{Factory=newCustomMongoFactory()};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

Notes

  • You can override other virtual methods on MongoWriteOnlyTransaction (for example SignalJobsAddedToQueues or Log) to change notifications or debug output.
  • Use a custom factory when you need to swap multiple internal components; override several Create... methods as needed.

Migration and backups

The library supports migration strategies to handle schema changes between releases. Choose the strategy that fits your operational needs:

  • Throw (default): refuse to start when a schema version mismatch is detected.
  • Drop: drop Hangfire collections and recreate schema from scratch (data loss).
  • Migrate: attempt to migrate data forward. May not preserve all data — test carefully.

Backup strategies

  • None: do not perform backups before migration.
  • Collection clone: copy collections within the database before applying migrations.
  • Custom: implement MongoBackupStrategy to provide a bespoke backup mechanism (e.g., export to files or another database).

Example configuration snippet:

varmigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()};varstorageOptions=newMongoStorageOptions{MigrationOptions=migrationOptions,InvisibilityTimeout=TimeSpan.FromMinutes(30)};GlobalConfiguration.Configuration.UseMongoStorage("<connection string with database name>",storageOptions);

Naming conventions

Hangfire.Mongo enforces PascalCase for its internal collections and will ignore application-wide convention packs (such as CamelCaseElementNameConvention) for Hangfire collections. This ensures schema stability across applications using different conventions.

Features summary

  • Durable job and state storage in MongoDB.
  • Multiple queue notification strategies: change streams (Watch), polling (Poll), and tailable notifications (TailNotificationsCollection).
  • Schema migration and configurable backup strategies.
  • Pluggable MongoFactory for customizing collections, indexes and serializers.
  • Swappable UTC date/time strategies for fine-grained date handling.
  • Configurable collection prefixing and connection checks.
  • Compatible with MongoDB and MongoDB-compatible services (including Cosmos DB using the MongoDB API).

Contributing

Contributions are welcome. When submitting changes:

  • Add tests for new behavior (if applicable).
  • Document breaking changes and migration steps.
  • Include migration/backup code when modifying schema.

Contributors

License

Hangfire.Mongo is released under the MIT License. See the LICENSE file for details.

About

Mongo DB support for Hangfire

Resources

Stars

281 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - gottscj/Hangfire.Mongo: Mongo DB support for Hangfire · GitHub
Skip to content

Latest commit

History

458 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Hangfire.Mongo

BuildNuGet downloadsLicense

A MongoDB storage provider for Hangfire. Use MongoDB-compatible servers (including Azure Cosmos DB configured with the MongoDB API, and AWS DocumentDB) to persist and process Hangfire jobs.

Why Hangfire.Mongo?

  • Reliable job storage and state management in MongoDB.
  • Multiple queue notification strategies (change streams, tailable collections, polling).
  • Schema migration and backup strategies with configurable behavior.
  • Extension points to customize collection creation, serialization and UTC handling.
  • Works with ASP.NET Core and console-hosted Hangfire servers.

Prerequisites

  • .NET Standard / .NET Core compatible runtime used by your application.
  • MongoDB server (community, Atlas, or other compatible servers). For Cosmos DB use the MongoDB API endpoint.

Hangfire (project and docs)

Installation

Install from NuGet (recommended):

dotnet add package Hangfire.Mongo

Or via the Package Manager Console in Visual Studio:

PM> Install-Package Hangfire.Mongo

Quick start — ASP.NET Core

Add Hangfire and Hangfire.Mongo in your Startup/Program configuration:

// Program.cs or Startup.csvarmongoUrl=newMongoUrl("mongodb://localhost:27017/jobs");varmongoClient=newMongoClient(mongoUrl.ToMongoUrl());services.AddHangfire(configuration =>configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseMongoStorage(mongoClient,mongoUrl.DatabaseName,newMongoStorageOptions{Prefix="hangfire.mongo",CheckConnection=true,MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}}));services.AddHangfireServer();

Quick start — Console

varoptions=newMongoStorageOptions{MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newDropMongoMigrationStrategy(),BackupStrategy=newNoneMongoBackupStrategy()}};usingvarstorage=newMongoStorage(MongoClientSettings.FromConnectionString("mongodb://localhost:27017"),"jobs",options);usingvarserver=newBackgroundJobServer(storage);

Configuration highlights

  • Prefix: prefix for Hangfire collection names (default: no prefix).
  • CheckConnection: verify connectivity at startup (recommended for production).
  • InvisibilityTimeout: controls how long a job remains in Processing before becoming visible again; configure to avoid stuck jobs.
  • CheckQueuedJobsStrategy: choose between Watch (change streams), Poll, or TailNotificationsCollection.

Cosmos DB (MongoDB API) — Getting started

Hangfire.Mongo works with Azure Cosmos DB only when the Cosmos account is configured to use the MongoDB API. The SQL API is not compatible with the MongoDB driver and therefore not supported.

Important: this project includes a specialized options type, CosmosStorageOptions (in Hangfire.Mongo.CosmosDB), which adjusts a number of settings that are required or recommended for Cosmos DB. Use CosmosStorageOptions instead of MongoStorageOptions when targeting Cosmos DB.

Key overrides in CosmosStorageOptions

  • CheckQueuedJobsStrategy = Poll
    • Cosmos DB does not reliably support change streams or tailable capped collections in the same way as a regular MongoDB server; polling is the safe strategy.
  • CheckConnection = false
    • Cosmos DB's connection semantics and the way it handles metadata can make the generic startup connection check unsuitable; the Cosmos-specific options disable the default connection ping.
  • SupportsCappedCollection = false
    • Cosmos DB (Mongo API) does not support capped collections — tailing a notifications collection is not available.
  • MigrationLockTimeout = 2 minutes
    • Increased timeout to accommodate Cosmos DB's operational latencies.
  • Factory = new CosmosFactory()
    • A Cosmos-specific factory is used to create storage components tuned for Cosmos behavior.
  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • The UTC date/time strategy is tuned for Cosmos' server responses; this replaces the default set of strategies.

⚠️Note on testing and support

Because access to Azure Cosmos DB (MongoDB API) is limited in the project's test environment, the Cosmos-specific configuration and code paths are not as exhaustively tested as the standard MongoDB implementation. If you use Cosmos DB and encounter issues, please open an issue or submit a PR — community feedback and contributions are appreciated and will help improve compatibility. I will rely on community help to identify and fix provider-specific bugs that cannot be validated in the project's CI/test environment.

Example — recommended Cosmos setup

usingHangfire.Mongo.CosmosDB;varmongoUrl=newMongoUrl("mongodb://<user>:<password>@<your-account>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb");varclient=newMongoClient(mongoUrl.ToMongoUrl());varoptions=newCosmosStorageOptions{// CosmosStorageOptions already sets recommended defaults for Cosmos// You can still tweak other options here if necessary (timeouts, prefix, migration options...)Prefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core pattern: use the Hangfire configuration lambda and call the Cosmos-specific// extension method `UseCosmosStorage` provided in `CosmosBootstrapperConfigurationExtensions`.// This registers the storage with Hangfire and returns the created `CosmosStorage` instance.services.AddHangfire(cfg =>cfg.UseCosmosStorage(client,"<database>",options));services.AddHangfireServer();
// Non-ASP.NET Core / GlobalConfiguration pattern:usingHangfire;usingHangfire.Mongo.CosmosDB;// Register Cosmos storage on the global Hangfire configuration and capture the returned storagevarstorage=GlobalConfiguration.Configuration.UseCosmosStorage(client,"<database>",options);// Create a server that uses the registered storageusingvarserver=newBackgroundJobServer(storage);

Notes:

  • The UseCosmosStorage extension method lives in the Hangfire.Mongo.CosmosDB namespace; add using Hangfire.Mongo.CosmosDB; to access it.
  • The extension wraps construction of CosmosStorage, registers it on the Hangfire global configuration, and returns the created storage instance so you can use it directly when creating a BackgroundJobServer if needed.

Implications and guidance

  • Do not rely on change-stream based notifications or tailable collections with Cosmos — the Poll strategy is used by default in CosmosStorageOptions.
  • CheckConnection is disabled by default for Cosmos; if you enable it you'll need Cosmos-specific checks and longer timeouts (not recommended).
  • Because SupportsCappedCollection is false, TailNotificationsCollection is not a valid CheckQueuedJobsStrategy for Cosmos.
  • CosmosFactory is used to wire Cosmos-specific implementations (e.g., connections, write semantics); if you need to customize behavior, consider subclassing CosmosFactory rather than the base MongoFactory.
  • UTC date/time handling for Cosmos is tuned via IsMasterUtcDateTimeStrategy — if you replace it, ensure any custom strategy matches Cosmos' server response behavior.

DocumentDB (AWS DocumentDB / Mongo-compatible)

This repository provides a DocumentDbStorage path for Mongo-compatible DocumentDB servers (for example AWS DocumentDB). This is intended for MongoDB-compatible services that restrict certain admin commands or have slightly different server responses compared to a full MongoDB server.

⚠️Note on testing and support

DocumentDB-compatible providers (such as AWS DocumentDB) are similarly less well-tested in this project due to limited access to those managed services during development. The DocumentDbStorageOptions and DocumentDB-specific code paths have been designed to be conservative, but if you find bugs or provider-specific issues please report them or contribute fixes — community help is essential for robust support. I will rely on community contributions and reports to discover and resolve provider-specific issues that cannot be exercised in the project's automated tests.

Use DocumentDbStorageOptions (in Hangfire.Mongo.DocumentDB) when targeting DocumentDB-compatible services. The DocumentDbStorageOptions constructor narrows the UTC date/time strategies to use IsMasterUtcDateTimeStrategy, because unprivileged users on these services may not be able to run higher-privileged commands used by other strategies.

Key points about DocumentDbStorageOptions

  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • Restricts date/time probing to the isMaster command which is generally available to unprivileged users on DocumentDB implementations.
  • Other storage options retain the defaults from MongoStorageOptions unless you override them.

How to use

usingHangfire.Mongo.DocumentDB;varclient=newMongoClient("mongodb://<user>:<password>@<your-docdb-host>:27017/?ssl=true");varoptions=newDocumentDbStorageOptions{// You can still customize prefix, migration options, and other MongoStorageOptions membersPrefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core patternservices.AddHangfire(cfg =>cfg.UseDocumentDbStorage(client,"<database>",options));services.AddHangfireServer();// Non-ASP.NET Core / GlobalConfiguration patternvarstorage=GlobalConfiguration.Configuration.UseDocumentDbStorage(client,"<database>",options);usingvarserver=newBackgroundJobServer(storage);

Notes and guidance

  • UseDocumentDbStorage is implemented in DocumentDbBootstrapperConfigurationExtensions (namespace Hangfire.Mongo.DocumentDB). Add using Hangfire.Mongo.DocumentDB; to access it.
  • DocumentDB-compatible services may require TLS/SSL and specific MongoDB driver settings; ensure MongoClientSettings are tuned for your provider (timeouts, retry policy, TLS settings).
  • Because DocumentDbStorageOptions narrows UTC probing to isMaster, it is safer to run with unprivileged users. If you need a different strategy, provide a custom UtcDateTimeStrategy but test carefully against your provider.
  • If your provider exposes additional incompatibilities (capped collections, change streams, etc.), adjust MongoStorageOptions flags (for example SupportsCappedCollection) or use CheckQueuedJobsStrategy = CheckQueuedJobsStrategy.Poll when change-streams/tailable collections are not available.
  • If you need provider-specific creation/wiring logic, consider subclassing the provided DocumentDbStorage or CosmosFactory/MongoFactory patterns as appropriate.

Extending the library

The project provides well-known extension points for advanced customization. Two common extension points are MongoFactory and the UTC date/time strategies.

Note: most classes and methods in this library are public and many are virtual (for example MongoFactory, MongoWriteOnlyTransaction, MongoConnection and related components). This design allows you to subclass and override behaviour at many points — you can swap internal components, change commit behavior, alter notification logic, or plug-in custom serialization by overriding the appropriate virtual methods.

In short: almost all methods are public and many are virtual, so you can change almost any behaviour by subclassing and overriding the provided components.

  1. Overriding MongoFactory

MongoFactory is the place where MongoDB collections, indexes and other components are created. By providing a custom implementation you can:

  • Create custom indexes or collection options,
  • Plug-in custom DTO serialization or mapping,
  • Swap collection implementations for testing.

Accurate examples (based on the real MongoFactory API):

// Example 1: override the database context creation to enforce a custom prefixpublicclassCustomMongoFactory:MongoFactory{publicoverrideHangfireDbContextCreateDbContext(IMongoClientmongoClient,stringdatabaseName,stringprefix){// Force a different prefix for all Hangfire collectionsvarenforcedPrefix="myapp.hangfire";returnbase.CreateDbContext(mongoClient,databaseName,enforcedPrefix);}}
// Example 2: override the distributed lock creation to change resource naming (or add instrumentation)publicclassCustomMongoFactoryWithLocks:MongoFactory{publicoverrideMongoDistributedLockCreateMongoDistributedLock(stringresource,TimeSpantimeout,HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){// Use an application-specific prefix for the lock resource namevarcustomResource=$"MyAppLock:{resource}";// You could also wrap the returned lock with your own implementation that adds logging/metricsreturnnewMongoDistributedLock(customResource,timeout,dbContext,storageOptions);}}

Wiring a custom factory

  • MongoStorageOptions exposes a Factory property. Assign your custom factory before creating MongoStorage or before calling UseMongoStorage:
varoptions=newMongoStorageOptions{Factory=newCustomMongoFactory(),};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

If you need to customize other behaviors (job fetching, notifications, expiration manager etc.), inspect the available virtual methods on MongoFactory and override the appropriate creation method (for example CreateMongoJobFetcher, CreateMongoNotificationObserver, CreateMongoExpirationManager).

  1. Custom UTC date/time strategies

Date/time serialization is important for cross-platform correctness and compatibility with various MongoDB servers. The library exposes swappable UTC strategies (look for implementations under UtcDateTime or similar namespaces) so you can control how DateTime values are serialized and deserialized.

Example custom strategy:

publicclassCustomUtcDateTimeStrategy:UtcDateTimeStrategy{publicoverrideBsonValueSerialize(DateTimedateTime){// Force DateTime to UTC and store as BsonDateTimereturnnewBsonDateTime(DateTime.SpecifyKind(dateTime,DateTimeKind.Utc));}publicoverrideDateTimeDeserialize(BsonValuevalue){returnvalue.AsBsonDateTime.ToUniversalTime();}}

Wiring the strategy

  • Set MongoStorageOptions.UtcDateTimeStrategies to an array of the strategies you want to use (in order of preference). This property is an array of UtcDateTimeStrategy instances and should be configured before creating MongoStorage / calling UseMongoStorage.

Example:

varoptions=newMongoStorageOptions{UtcDateTimeStrategies=newUtcDateTimeStrategy[]{newCustomUtcDateTimeStrategy(),newAggregationUtcDateTimeStrategy(),newServerStatusUtcDateTimeStrategy()}};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));
  • Alternative: if you need lower-level control (for example registering Bson serializers or setting up class maps) you can wire the strategy inside a custom MongoFactory implementation — the factory is invoked when the storage constructs its internal components, so it can be used to ensure serializers and mappings are registered before collections are used.

Example — customize MongoWriteOnlyTransaction

A deeper extension point is MongoWriteOnlyTransaction. You can subclass it to alter commit behavior, add retries, instrumentation or change how notifications are signalled. Below is a compact example that:

  • Subclasses MongoWriteOnlyTransaction and overrides ExecuteCommit to add a retry loop,
  • Supplies the custom transaction from a custom MongoFactory, and
  • Wires the factory via MongoStorageOptions.Factory.
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;usingMongoDB.Bson;usingMongoDB.Driver;usingHangfire.Mongo.Database;// 1) Custom transaction with a simple retry around the bulk commitpublicclassCustomMongoWriteOnlyTransaction:MongoWriteOnlyTransaction{publicCustomMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions):base(dbContext,storageOptions){}protectedoverridevoidExecuteCommit(IMongoCollection<BsonDocument>jobGraph,List<WriteModel<BsonDocument>>writeModels,BulkWriteOptionsbulkWriteOptions){constintmaxAttempts=3;intattempt=0;while(true){try{// use base behavior for actual bulk writebase.ExecuteCommit(jobGraph,writeModels,bulkWriteOptions);return;}catch(MongoException)when(++attempt<maxAttempts){// simple backoff; replace with your preferred retry policy or instrumentationThread.Sleep(200*attempt);}}}}// 2) Custom factory that returns the custom transactionpublicclassCustomMongoFactory:MongoFactory{publicoverrideMongoWriteOnlyTransactionCreateMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){returnnewCustomMongoWriteOnlyTransaction(dbContext,storageOptions);}}// 3) Wiring via optionsvaroptions=newMongoStorageOptions{Factory=newCustomMongoFactory()};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

Notes

  • You can override other virtual methods on MongoWriteOnlyTransaction (for example SignalJobsAddedToQueues or Log) to change notifications or debug output.
  • Use a custom factory when you need to swap multiple internal components; override several Create... methods as needed.

Migration and backups

The library supports migration strategies to handle schema changes between releases. Choose the strategy that fits your operational needs:

  • Throw (default): refuse to start when a schema version mismatch is detected.
  • Drop: drop Hangfire collections and recreate schema from scratch (data loss).
  • Migrate: attempt to migrate data forward. May not preserve all data — test carefully.

Backup strategies

  • None: do not perform backups before migration.
  • Collection clone: copy collections within the database before applying migrations.
  • Custom: implement MongoBackupStrategy to provide a bespoke backup mechanism (e.g., export to files or another database).

Example configuration snippet:

varmigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()};varstorageOptions=newMongoStorageOptions{MigrationOptions=migrationOptions,InvisibilityTimeout=TimeSpan.FromMinutes(30)};GlobalConfiguration.Configuration.UseMongoStorage("<connection string with database name>",storageOptions);

Naming conventions

Hangfire.Mongo enforces PascalCase for its internal collections and will ignore application-wide convention packs (such as CamelCaseElementNameConvention) for Hangfire collections. This ensures schema stability across applications using different conventions.

Features summary

  • Durable job and state storage in MongoDB.
  • Multiple queue notification strategies: change streams (Watch), polling (Poll), and tailable notifications (TailNotificationsCollection).
  • Schema migration and configurable backup strategies.
  • Pluggable MongoFactory for customizing collections, indexes and serializers.
  • Swappable UTC date/time strategies for fine-grained date handling.
  • Configurable collection prefixing and connection checks.
  • Compatible with MongoDB and MongoDB-compatible services (including Cosmos DB using the MongoDB API).

Contributing

Contributions are welcome. When submitting changes:

  • Add tests for new behavior (if applicable).
  • Document breaking changes and migration steps.
  • Include migration/backup code when modifying schema.

Contributors

License

Hangfire.Mongo is released under the MIT License. See the LICENSE file for details.

About

Mongo DB support for Hangfire

Resources

Stars

281 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - gottscj/Hangfire.Mongo: Mongo DB support for Hangfire · GitHub
Skip to content

Latest commit

History

458 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Hangfire.Mongo

BuildNuGet downloadsLicense

A MongoDB storage provider for Hangfire. Use MongoDB-compatible servers (including Azure Cosmos DB configured with the MongoDB API, and AWS DocumentDB) to persist and process Hangfire jobs.

Why Hangfire.Mongo?

  • Reliable job storage and state management in MongoDB.
  • Multiple queue notification strategies (change streams, tailable collections, polling).
  • Schema migration and backup strategies with configurable behavior.
  • Extension points to customize collection creation, serialization and UTC handling.
  • Works with ASP.NET Core and console-hosted Hangfire servers.

Prerequisites

  • .NET Standard / .NET Core compatible runtime used by your application.
  • MongoDB server (community, Atlas, or other compatible servers). For Cosmos DB use the MongoDB API endpoint.

Hangfire (project and docs)

Installation

Install from NuGet (recommended):

dotnet add package Hangfire.Mongo

Or via the Package Manager Console in Visual Studio:

PM> Install-Package Hangfire.Mongo

Quick start — ASP.NET Core

Add Hangfire and Hangfire.Mongo in your Startup/Program configuration:

// Program.cs or Startup.csvarmongoUrl=newMongoUrl("mongodb://localhost:27017/jobs");varmongoClient=newMongoClient(mongoUrl.ToMongoUrl());services.AddHangfire(configuration =>configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseMongoStorage(mongoClient,mongoUrl.DatabaseName,newMongoStorageOptions{Prefix="hangfire.mongo",CheckConnection=true,MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}}));services.AddHangfireServer();

Quick start — Console

varoptions=newMongoStorageOptions{MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newDropMongoMigrationStrategy(),BackupStrategy=newNoneMongoBackupStrategy()}};usingvarstorage=newMongoStorage(MongoClientSettings.FromConnectionString("mongodb://localhost:27017"),"jobs",options);usingvarserver=newBackgroundJobServer(storage);

Configuration highlights

  • Prefix: prefix for Hangfire collection names (default: no prefix).
  • CheckConnection: verify connectivity at startup (recommended for production).
  • InvisibilityTimeout: controls how long a job remains in Processing before becoming visible again; configure to avoid stuck jobs.
  • CheckQueuedJobsStrategy: choose between Watch (change streams), Poll, or TailNotificationsCollection.

Cosmos DB (MongoDB API) — Getting started

Hangfire.Mongo works with Azure Cosmos DB only when the Cosmos account is configured to use the MongoDB API. The SQL API is not compatible with the MongoDB driver and therefore not supported.

Important: this project includes a specialized options type, CosmosStorageOptions (in Hangfire.Mongo.CosmosDB), which adjusts a number of settings that are required or recommended for Cosmos DB. Use CosmosStorageOptions instead of MongoStorageOptions when targeting Cosmos DB.

Key overrides in CosmosStorageOptions

  • CheckQueuedJobsStrategy = Poll
    • Cosmos DB does not reliably support change streams or tailable capped collections in the same way as a regular MongoDB server; polling is the safe strategy.
  • CheckConnection = false
    • Cosmos DB's connection semantics and the way it handles metadata can make the generic startup connection check unsuitable; the Cosmos-specific options disable the default connection ping.
  • SupportsCappedCollection = false
    • Cosmos DB (Mongo API) does not support capped collections — tailing a notifications collection is not available.
  • MigrationLockTimeout = 2 minutes
    • Increased timeout to accommodate Cosmos DB's operational latencies.
  • Factory = new CosmosFactory()
    • A Cosmos-specific factory is used to create storage components tuned for Cosmos behavior.
  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • The UTC date/time strategy is tuned for Cosmos' server responses; this replaces the default set of strategies.

⚠️Note on testing and support

Because access to Azure Cosmos DB (MongoDB API) is limited in the project's test environment, the Cosmos-specific configuration and code paths are not as exhaustively tested as the standard MongoDB implementation. If you use Cosmos DB and encounter issues, please open an issue or submit a PR — community feedback and contributions are appreciated and will help improve compatibility. I will rely on community help to identify and fix provider-specific bugs that cannot be validated in the project's CI/test environment.

Example — recommended Cosmos setup

usingHangfire.Mongo.CosmosDB;varmongoUrl=newMongoUrl("mongodb://<user>:<password>@<your-account>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb");varclient=newMongoClient(mongoUrl.ToMongoUrl());varoptions=newCosmosStorageOptions{// CosmosStorageOptions already sets recommended defaults for Cosmos// You can still tweak other options here if necessary (timeouts, prefix, migration options...)Prefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core pattern: use the Hangfire configuration lambda and call the Cosmos-specific// extension method `UseCosmosStorage` provided in `CosmosBootstrapperConfigurationExtensions`.// This registers the storage with Hangfire and returns the created `CosmosStorage` instance.services.AddHangfire(cfg =>cfg.UseCosmosStorage(client,"<database>",options));services.AddHangfireServer();
// Non-ASP.NET Core / GlobalConfiguration pattern:usingHangfire;usingHangfire.Mongo.CosmosDB;// Register Cosmos storage on the global Hangfire configuration and capture the returned storagevarstorage=GlobalConfiguration.Configuration.UseCosmosStorage(client,"<database>",options);// Create a server that uses the registered storageusingvarserver=newBackgroundJobServer(storage);

Notes:

  • The UseCosmosStorage extension method lives in the Hangfire.Mongo.CosmosDB namespace; add using Hangfire.Mongo.CosmosDB; to access it.
  • The extension wraps construction of CosmosStorage, registers it on the Hangfire global configuration, and returns the created storage instance so you can use it directly when creating a BackgroundJobServer if needed.

Implications and guidance

  • Do not rely on change-stream based notifications or tailable collections with Cosmos — the Poll strategy is used by default in CosmosStorageOptions.
  • CheckConnection is disabled by default for Cosmos; if you enable it you'll need Cosmos-specific checks and longer timeouts (not recommended).
  • Because SupportsCappedCollection is false, TailNotificationsCollection is not a valid CheckQueuedJobsStrategy for Cosmos.
  • CosmosFactory is used to wire Cosmos-specific implementations (e.g., connections, write semantics); if you need to customize behavior, consider subclassing CosmosFactory rather than the base MongoFactory.
  • UTC date/time handling for Cosmos is tuned via IsMasterUtcDateTimeStrategy — if you replace it, ensure any custom strategy matches Cosmos' server response behavior.

DocumentDB (AWS DocumentDB / Mongo-compatible)

This repository provides a DocumentDbStorage path for Mongo-compatible DocumentDB servers (for example AWS DocumentDB). This is intended for MongoDB-compatible services that restrict certain admin commands or have slightly different server responses compared to a full MongoDB server.

⚠️Note on testing and support

DocumentDB-compatible providers (such as AWS DocumentDB) are similarly less well-tested in this project due to limited access to those managed services during development. The DocumentDbStorageOptions and DocumentDB-specific code paths have been designed to be conservative, but if you find bugs or provider-specific issues please report them or contribute fixes — community help is essential for robust support. I will rely on community contributions and reports to discover and resolve provider-specific issues that cannot be exercised in the project's automated tests.

Use DocumentDbStorageOptions (in Hangfire.Mongo.DocumentDB) when targeting DocumentDB-compatible services. The DocumentDbStorageOptions constructor narrows the UTC date/time strategies to use IsMasterUtcDateTimeStrategy, because unprivileged users on these services may not be able to run higher-privileged commands used by other strategies.

Key points about DocumentDbStorageOptions

  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • Restricts date/time probing to the isMaster command which is generally available to unprivileged users on DocumentDB implementations.
  • Other storage options retain the defaults from MongoStorageOptions unless you override them.

How to use

usingHangfire.Mongo.DocumentDB;varclient=newMongoClient("mongodb://<user>:<password>@<your-docdb-host>:27017/?ssl=true");varoptions=newDocumentDbStorageOptions{// You can still customize prefix, migration options, and other MongoStorageOptions membersPrefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core patternservices.AddHangfire(cfg =>cfg.UseDocumentDbStorage(client,"<database>",options));services.AddHangfireServer();// Non-ASP.NET Core / GlobalConfiguration patternvarstorage=GlobalConfiguration.Configuration.UseDocumentDbStorage(client,"<database>",options);usingvarserver=newBackgroundJobServer(storage);

Notes and guidance

  • UseDocumentDbStorage is implemented in DocumentDbBootstrapperConfigurationExtensions (namespace Hangfire.Mongo.DocumentDB). Add using Hangfire.Mongo.DocumentDB; to access it.
  • DocumentDB-compatible services may require TLS/SSL and specific MongoDB driver settings; ensure MongoClientSettings are tuned for your provider (timeouts, retry policy, TLS settings).
  • Because DocumentDbStorageOptions narrows UTC probing to isMaster, it is safer to run with unprivileged users. If you need a different strategy, provide a custom UtcDateTimeStrategy but test carefully against your provider.
  • If your provider exposes additional incompatibilities (capped collections, change streams, etc.), adjust MongoStorageOptions flags (for example SupportsCappedCollection) or use CheckQueuedJobsStrategy = CheckQueuedJobsStrategy.Poll when change-streams/tailable collections are not available.
  • If you need provider-specific creation/wiring logic, consider subclassing the provided DocumentDbStorage or CosmosFactory/MongoFactory patterns as appropriate.

Extending the library

The project provides well-known extension points for advanced customization. Two common extension points are MongoFactory and the UTC date/time strategies.

Note: most classes and methods in this library are public and many are virtual (for example MongoFactory, MongoWriteOnlyTransaction, MongoConnection and related components). This design allows you to subclass and override behaviour at many points — you can swap internal components, change commit behavior, alter notification logic, or plug-in custom serialization by overriding the appropriate virtual methods.

In short: almost all methods are public and many are virtual, so you can change almost any behaviour by subclassing and overriding the provided components.

  1. Overriding MongoFactory

MongoFactory is the place where MongoDB collections, indexes and other components are created. By providing a custom implementation you can:

  • Create custom indexes or collection options,
  • Plug-in custom DTO serialization or mapping,
  • Swap collection implementations for testing.

Accurate examples (based on the real MongoFactory API):

// Example 1: override the database context creation to enforce a custom prefixpublicclassCustomMongoFactory:MongoFactory{publicoverrideHangfireDbContextCreateDbContext(IMongoClientmongoClient,stringdatabaseName,stringprefix){// Force a different prefix for all Hangfire collectionsvarenforcedPrefix="myapp.hangfire";returnbase.CreateDbContext(mongoClient,databaseName,enforcedPrefix);}}
// Example 2: override the distributed lock creation to change resource naming (or add instrumentation)publicclassCustomMongoFactoryWithLocks:MongoFactory{publicoverrideMongoDistributedLockCreateMongoDistributedLock(stringresource,TimeSpantimeout,HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){// Use an application-specific prefix for the lock resource namevarcustomResource=$"MyAppLock:{resource}";// You could also wrap the returned lock with your own implementation that adds logging/metricsreturnnewMongoDistributedLock(customResource,timeout,dbContext,storageOptions);}}

Wiring a custom factory

  • MongoStorageOptions exposes a Factory property. Assign your custom factory before creating MongoStorage or before calling UseMongoStorage:
varoptions=newMongoStorageOptions{Factory=newCustomMongoFactory(),};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

If you need to customize other behaviors (job fetching, notifications, expiration manager etc.), inspect the available virtual methods on MongoFactory and override the appropriate creation method (for example CreateMongoJobFetcher, CreateMongoNotificationObserver, CreateMongoExpirationManager).

  1. Custom UTC date/time strategies

Date/time serialization is important for cross-platform correctness and compatibility with various MongoDB servers. The library exposes swappable UTC strategies (look for implementations under UtcDateTime or similar namespaces) so you can control how DateTime values are serialized and deserialized.

Example custom strategy:

publicclassCustomUtcDateTimeStrategy:UtcDateTimeStrategy{publicoverrideBsonValueSerialize(DateTimedateTime){// Force DateTime to UTC and store as BsonDateTimereturnnewBsonDateTime(DateTime.SpecifyKind(dateTime,DateTimeKind.Utc));}publicoverrideDateTimeDeserialize(BsonValuevalue){returnvalue.AsBsonDateTime.ToUniversalTime();}}

Wiring the strategy

  • Set MongoStorageOptions.UtcDateTimeStrategies to an array of the strategies you want to use (in order of preference). This property is an array of UtcDateTimeStrategy instances and should be configured before creating MongoStorage / calling UseMongoStorage.

Example:

varoptions=newMongoStorageOptions{UtcDateTimeStrategies=newUtcDateTimeStrategy[]{newCustomUtcDateTimeStrategy(),newAggregationUtcDateTimeStrategy(),newServerStatusUtcDateTimeStrategy()}};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));
  • Alternative: if you need lower-level control (for example registering Bson serializers or setting up class maps) you can wire the strategy inside a custom MongoFactory implementation — the factory is invoked when the storage constructs its internal components, so it can be used to ensure serializers and mappings are registered before collections are used.

Example — customize MongoWriteOnlyTransaction

A deeper extension point is MongoWriteOnlyTransaction. You can subclass it to alter commit behavior, add retries, instrumentation or change how notifications are signalled. Below is a compact example that:

  • Subclasses MongoWriteOnlyTransaction and overrides ExecuteCommit to add a retry loop,
  • Supplies the custom transaction from a custom MongoFactory, and
  • Wires the factory via MongoStorageOptions.Factory.
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;usingMongoDB.Bson;usingMongoDB.Driver;usingHangfire.Mongo.Database;// 1) Custom transaction with a simple retry around the bulk commitpublicclassCustomMongoWriteOnlyTransaction:MongoWriteOnlyTransaction{publicCustomMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions):base(dbContext,storageOptions){}protectedoverridevoidExecuteCommit(IMongoCollection<BsonDocument>jobGraph,List<WriteModel<BsonDocument>>writeModels,BulkWriteOptionsbulkWriteOptions){constintmaxAttempts=3;intattempt=0;while(true){try{// use base behavior for actual bulk writebase.ExecuteCommit(jobGraph,writeModels,bulkWriteOptions);return;}catch(MongoException)when(++attempt<maxAttempts){// simple backoff; replace with your preferred retry policy or instrumentationThread.Sleep(200*attempt);}}}}// 2) Custom factory that returns the custom transactionpublicclassCustomMongoFactory:MongoFactory{publicoverrideMongoWriteOnlyTransactionCreateMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){returnnewCustomMongoWriteOnlyTransaction(dbContext,storageOptions);}}// 3) Wiring via optionsvaroptions=newMongoStorageOptions{Factory=newCustomMongoFactory()};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

Notes

  • You can override other virtual methods on MongoWriteOnlyTransaction (for example SignalJobsAddedToQueues or Log) to change notifications or debug output.
  • Use a custom factory when you need to swap multiple internal components; override several Create... methods as needed.

Migration and backups

The library supports migration strategies to handle schema changes between releases. Choose the strategy that fits your operational needs:

  • Throw (default): refuse to start when a schema version mismatch is detected.
  • Drop: drop Hangfire collections and recreate schema from scratch (data loss).
  • Migrate: attempt to migrate data forward. May not preserve all data — test carefully.

Backup strategies

  • None: do not perform backups before migration.
  • Collection clone: copy collections within the database before applying migrations.
  • Custom: implement MongoBackupStrategy to provide a bespoke backup mechanism (e.g., export to files or another database).

Example configuration snippet:

varmigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()};varstorageOptions=newMongoStorageOptions{MigrationOptions=migrationOptions,InvisibilityTimeout=TimeSpan.FromMinutes(30)};GlobalConfiguration.Configuration.UseMongoStorage("<connection string with database name>",storageOptions);

Naming conventions

Hangfire.Mongo enforces PascalCase for its internal collections and will ignore application-wide convention packs (such as CamelCaseElementNameConvention) for Hangfire collections. This ensures schema stability across applications using different conventions.

Features summary

  • Durable job and state storage in MongoDB.
  • Multiple queue notification strategies: change streams (Watch), polling (Poll), and tailable notifications (TailNotificationsCollection).
  • Schema migration and configurable backup strategies.
  • Pluggable MongoFactory for customizing collections, indexes and serializers.
  • Swappable UTC date/time strategies for fine-grained date handling.
  • Configurable collection prefixing and connection checks.
  • Compatible with MongoDB and MongoDB-compatible services (including Cosmos DB using the MongoDB API).

Contributing

Contributions are welcome. When submitting changes:

  • Add tests for new behavior (if applicable).
  • Document breaking changes and migration steps.
  • Include migration/backup code when modifying schema.

Contributors

License

Hangfire.Mongo is released under the MIT License. See the LICENSE file for details.

About

Mongo DB support for Hangfire

Resources

Stars

281 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - gottscj/Hangfire.Mongo: Mongo DB support for Hangfire · GitHub
Skip to content

Latest commit

History

458 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Hangfire.Mongo

BuildNuGet downloadsLicense

A MongoDB storage provider for Hangfire. Use MongoDB-compatible servers (including Azure Cosmos DB configured with the MongoDB API, and AWS DocumentDB) to persist and process Hangfire jobs.

Why Hangfire.Mongo?

  • Reliable job storage and state management in MongoDB.
  • Multiple queue notification strategies (change streams, tailable collections, polling).
  • Schema migration and backup strategies with configurable behavior.
  • Extension points to customize collection creation, serialization and UTC handling.
  • Works with ASP.NET Core and console-hosted Hangfire servers.

Prerequisites

  • .NET Standard / .NET Core compatible runtime used by your application.
  • MongoDB server (community, Atlas, or other compatible servers). For Cosmos DB use the MongoDB API endpoint.

Hangfire (project and docs)

Installation

Install from NuGet (recommended):

dotnet add package Hangfire.Mongo

Or via the Package Manager Console in Visual Studio:

PM> Install-Package Hangfire.Mongo

Quick start — ASP.NET Core

Add Hangfire and Hangfire.Mongo in your Startup/Program configuration:

// Program.cs or Startup.csvarmongoUrl=newMongoUrl("mongodb://localhost:27017/jobs");varmongoClient=newMongoClient(mongoUrl.ToMongoUrl());services.AddHangfire(configuration =>configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseMongoStorage(mongoClient,mongoUrl.DatabaseName,newMongoStorageOptions{Prefix="hangfire.mongo",CheckConnection=true,MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}}));services.AddHangfireServer();

Quick start — Console

varoptions=newMongoStorageOptions{MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newDropMongoMigrationStrategy(),BackupStrategy=newNoneMongoBackupStrategy()}};usingvarstorage=newMongoStorage(MongoClientSettings.FromConnectionString("mongodb://localhost:27017"),"jobs",options);usingvarserver=newBackgroundJobServer(storage);

Configuration highlights

  • Prefix: prefix for Hangfire collection names (default: no prefix).
  • CheckConnection: verify connectivity at startup (recommended for production).
  • InvisibilityTimeout: controls how long a job remains in Processing before becoming visible again; configure to avoid stuck jobs.
  • CheckQueuedJobsStrategy: choose between Watch (change streams), Poll, or TailNotificationsCollection.

Cosmos DB (MongoDB API) — Getting started

Hangfire.Mongo works with Azure Cosmos DB only when the Cosmos account is configured to use the MongoDB API. The SQL API is not compatible with the MongoDB driver and therefore not supported.

Important: this project includes a specialized options type, CosmosStorageOptions (in Hangfire.Mongo.CosmosDB), which adjusts a number of settings that are required or recommended for Cosmos DB. Use CosmosStorageOptions instead of MongoStorageOptions when targeting Cosmos DB.

Key overrides in CosmosStorageOptions

  • CheckQueuedJobsStrategy = Poll
    • Cosmos DB does not reliably support change streams or tailable capped collections in the same way as a regular MongoDB server; polling is the safe strategy.
  • CheckConnection = false
    • Cosmos DB's connection semantics and the way it handles metadata can make the generic startup connection check unsuitable; the Cosmos-specific options disable the default connection ping.
  • SupportsCappedCollection = false
    • Cosmos DB (Mongo API) does not support capped collections — tailing a notifications collection is not available.
  • MigrationLockTimeout = 2 minutes
    • Increased timeout to accommodate Cosmos DB's operational latencies.
  • Factory = new CosmosFactory()
    • A Cosmos-specific factory is used to create storage components tuned for Cosmos behavior.
  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • The UTC date/time strategy is tuned for Cosmos' server responses; this replaces the default set of strategies.

⚠️Note on testing and support

Because access to Azure Cosmos DB (MongoDB API) is limited in the project's test environment, the Cosmos-specific configuration and code paths are not as exhaustively tested as the standard MongoDB implementation. If you use Cosmos DB and encounter issues, please open an issue or submit a PR — community feedback and contributions are appreciated and will help improve compatibility. I will rely on community help to identify and fix provider-specific bugs that cannot be validated in the project's CI/test environment.

Example — recommended Cosmos setup

usingHangfire.Mongo.CosmosDB;varmongoUrl=newMongoUrl("mongodb://<user>:<password>@<your-account>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb");varclient=newMongoClient(mongoUrl.ToMongoUrl());varoptions=newCosmosStorageOptions{// CosmosStorageOptions already sets recommended defaults for Cosmos// You can still tweak other options here if necessary (timeouts, prefix, migration options...)Prefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core pattern: use the Hangfire configuration lambda and call the Cosmos-specific// extension method `UseCosmosStorage` provided in `CosmosBootstrapperConfigurationExtensions`.// This registers the storage with Hangfire and returns the created `CosmosStorage` instance.services.AddHangfire(cfg =>cfg.UseCosmosStorage(client,"<database>",options));services.AddHangfireServer();
// Non-ASP.NET Core / GlobalConfiguration pattern:usingHangfire;usingHangfire.Mongo.CosmosDB;// Register Cosmos storage on the global Hangfire configuration and capture the returned storagevarstorage=GlobalConfiguration.Configuration.UseCosmosStorage(client,"<database>",options);// Create a server that uses the registered storageusingvarserver=newBackgroundJobServer(storage);

Notes:

  • The UseCosmosStorage extension method lives in the Hangfire.Mongo.CosmosDB namespace; add using Hangfire.Mongo.CosmosDB; to access it.
  • The extension wraps construction of CosmosStorage, registers it on the Hangfire global configuration, and returns the created storage instance so you can use it directly when creating a BackgroundJobServer if needed.

Implications and guidance

  • Do not rely on change-stream based notifications or tailable collections with Cosmos — the Poll strategy is used by default in CosmosStorageOptions.
  • CheckConnection is disabled by default for Cosmos; if you enable it you'll need Cosmos-specific checks and longer timeouts (not recommended).
  • Because SupportsCappedCollection is false, TailNotificationsCollection is not a valid CheckQueuedJobsStrategy for Cosmos.
  • CosmosFactory is used to wire Cosmos-specific implementations (e.g., connections, write semantics); if you need to customize behavior, consider subclassing CosmosFactory rather than the base MongoFactory.
  • UTC date/time handling for Cosmos is tuned via IsMasterUtcDateTimeStrategy — if you replace it, ensure any custom strategy matches Cosmos' server response behavior.

DocumentDB (AWS DocumentDB / Mongo-compatible)

This repository provides a DocumentDbStorage path for Mongo-compatible DocumentDB servers (for example AWS DocumentDB). This is intended for MongoDB-compatible services that restrict certain admin commands or have slightly different server responses compared to a full MongoDB server.

⚠️Note on testing and support

DocumentDB-compatible providers (such as AWS DocumentDB) are similarly less well-tested in this project due to limited access to those managed services during development. The DocumentDbStorageOptions and DocumentDB-specific code paths have been designed to be conservative, but if you find bugs or provider-specific issues please report them or contribute fixes — community help is essential for robust support. I will rely on community contributions and reports to discover and resolve provider-specific issues that cannot be exercised in the project's automated tests.

Use DocumentDbStorageOptions (in Hangfire.Mongo.DocumentDB) when targeting DocumentDB-compatible services. The DocumentDbStorageOptions constructor narrows the UTC date/time strategies to use IsMasterUtcDateTimeStrategy, because unprivileged users on these services may not be able to run higher-privileged commands used by other strategies.

Key points about DocumentDbStorageOptions

  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • Restricts date/time probing to the isMaster command which is generally available to unprivileged users on DocumentDB implementations.
  • Other storage options retain the defaults from MongoStorageOptions unless you override them.

How to use

usingHangfire.Mongo.DocumentDB;varclient=newMongoClient("mongodb://<user>:<password>@<your-docdb-host>:27017/?ssl=true");varoptions=newDocumentDbStorageOptions{// You can still customize prefix, migration options, and other MongoStorageOptions membersPrefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core patternservices.AddHangfire(cfg =>cfg.UseDocumentDbStorage(client,"<database>",options));services.AddHangfireServer();// Non-ASP.NET Core / GlobalConfiguration patternvarstorage=GlobalConfiguration.Configuration.UseDocumentDbStorage(client,"<database>",options);usingvarserver=newBackgroundJobServer(storage);

Notes and guidance

  • UseDocumentDbStorage is implemented in DocumentDbBootstrapperConfigurationExtensions (namespace Hangfire.Mongo.DocumentDB). Add using Hangfire.Mongo.DocumentDB; to access it.
  • DocumentDB-compatible services may require TLS/SSL and specific MongoDB driver settings; ensure MongoClientSettings are tuned for your provider (timeouts, retry policy, TLS settings).
  • Because DocumentDbStorageOptions narrows UTC probing to isMaster, it is safer to run with unprivileged users. If you need a different strategy, provide a custom UtcDateTimeStrategy but test carefully against your provider.
  • If your provider exposes additional incompatibilities (capped collections, change streams, etc.), adjust MongoStorageOptions flags (for example SupportsCappedCollection) or use CheckQueuedJobsStrategy = CheckQueuedJobsStrategy.Poll when change-streams/tailable collections are not available.
  • If you need provider-specific creation/wiring logic, consider subclassing the provided DocumentDbStorage or CosmosFactory/MongoFactory patterns as appropriate.

Extending the library

The project provides well-known extension points for advanced customization. Two common extension points are MongoFactory and the UTC date/time strategies.

Note: most classes and methods in this library are public and many are virtual (for example MongoFactory, MongoWriteOnlyTransaction, MongoConnection and related components). This design allows you to subclass and override behaviour at many points — you can swap internal components, change commit behavior, alter notification logic, or plug-in custom serialization by overriding the appropriate virtual methods.

In short: almost all methods are public and many are virtual, so you can change almost any behaviour by subclassing and overriding the provided components.

  1. Overriding MongoFactory

MongoFactory is the place where MongoDB collections, indexes and other components are created. By providing a custom implementation you can:

  • Create custom indexes or collection options,
  • Plug-in custom DTO serialization or mapping,
  • Swap collection implementations for testing.

Accurate examples (based on the real MongoFactory API):

// Example 1: override the database context creation to enforce a custom prefixpublicclassCustomMongoFactory:MongoFactory{publicoverrideHangfireDbContextCreateDbContext(IMongoClientmongoClient,stringdatabaseName,stringprefix){// Force a different prefix for all Hangfire collectionsvarenforcedPrefix="myapp.hangfire";returnbase.CreateDbContext(mongoClient,databaseName,enforcedPrefix);}}
// Example 2: override the distributed lock creation to change resource naming (or add instrumentation)publicclassCustomMongoFactoryWithLocks:MongoFactory{publicoverrideMongoDistributedLockCreateMongoDistributedLock(stringresource,TimeSpantimeout,HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){// Use an application-specific prefix for the lock resource namevarcustomResource=$"MyAppLock:{resource}";// You could also wrap the returned lock with your own implementation that adds logging/metricsreturnnewMongoDistributedLock(customResource,timeout,dbContext,storageOptions);}}

Wiring a custom factory

  • MongoStorageOptions exposes a Factory property. Assign your custom factory before creating MongoStorage or before calling UseMongoStorage:
varoptions=newMongoStorageOptions{Factory=newCustomMongoFactory(),};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

If you need to customize other behaviors (job fetching, notifications, expiration manager etc.), inspect the available virtual methods on MongoFactory and override the appropriate creation method (for example CreateMongoJobFetcher, CreateMongoNotificationObserver, CreateMongoExpirationManager).

  1. Custom UTC date/time strategies

Date/time serialization is important for cross-platform correctness and compatibility with various MongoDB servers. The library exposes swappable UTC strategies (look for implementations under UtcDateTime or similar namespaces) so you can control how DateTime values are serialized and deserialized.

Example custom strategy:

publicclassCustomUtcDateTimeStrategy:UtcDateTimeStrategy{publicoverrideBsonValueSerialize(DateTimedateTime){// Force DateTime to UTC and store as BsonDateTimereturnnewBsonDateTime(DateTime.SpecifyKind(dateTime,DateTimeKind.Utc));}publicoverrideDateTimeDeserialize(BsonValuevalue){returnvalue.AsBsonDateTime.ToUniversalTime();}}

Wiring the strategy

  • Set MongoStorageOptions.UtcDateTimeStrategies to an array of the strategies you want to use (in order of preference). This property is an array of UtcDateTimeStrategy instances and should be configured before creating MongoStorage / calling UseMongoStorage.

Example:

varoptions=newMongoStorageOptions{UtcDateTimeStrategies=newUtcDateTimeStrategy[]{newCustomUtcDateTimeStrategy(),newAggregationUtcDateTimeStrategy(),newServerStatusUtcDateTimeStrategy()}};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));
  • Alternative: if you need lower-level control (for example registering Bson serializers or setting up class maps) you can wire the strategy inside a custom MongoFactory implementation — the factory is invoked when the storage constructs its internal components, so it can be used to ensure serializers and mappings are registered before collections are used.

Example — customize MongoWriteOnlyTransaction

A deeper extension point is MongoWriteOnlyTransaction. You can subclass it to alter commit behavior, add retries, instrumentation or change how notifications are signalled. Below is a compact example that:

  • Subclasses MongoWriteOnlyTransaction and overrides ExecuteCommit to add a retry loop,
  • Supplies the custom transaction from a custom MongoFactory, and
  • Wires the factory via MongoStorageOptions.Factory.
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;usingMongoDB.Bson;usingMongoDB.Driver;usingHangfire.Mongo.Database;// 1) Custom transaction with a simple retry around the bulk commitpublicclassCustomMongoWriteOnlyTransaction:MongoWriteOnlyTransaction{publicCustomMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions):base(dbContext,storageOptions){}protectedoverridevoidExecuteCommit(IMongoCollection<BsonDocument>jobGraph,List<WriteModel<BsonDocument>>writeModels,BulkWriteOptionsbulkWriteOptions){constintmaxAttempts=3;intattempt=0;while(true){try{// use base behavior for actual bulk writebase.ExecuteCommit(jobGraph,writeModels,bulkWriteOptions);return;}catch(MongoException)when(++attempt<maxAttempts){// simple backoff; replace with your preferred retry policy or instrumentationThread.Sleep(200*attempt);}}}}// 2) Custom factory that returns the custom transactionpublicclassCustomMongoFactory:MongoFactory{publicoverrideMongoWriteOnlyTransactionCreateMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){returnnewCustomMongoWriteOnlyTransaction(dbContext,storageOptions);}}// 3) Wiring via optionsvaroptions=newMongoStorageOptions{Factory=newCustomMongoFactory()};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

Notes

  • You can override other virtual methods on MongoWriteOnlyTransaction (for example SignalJobsAddedToQueues or Log) to change notifications or debug output.
  • Use a custom factory when you need to swap multiple internal components; override several Create... methods as needed.

Migration and backups

The library supports migration strategies to handle schema changes between releases. Choose the strategy that fits your operational needs:

  • Throw (default): refuse to start when a schema version mismatch is detected.
  • Drop: drop Hangfire collections and recreate schema from scratch (data loss).
  • Migrate: attempt to migrate data forward. May not preserve all data — test carefully.

Backup strategies

  • None: do not perform backups before migration.
  • Collection clone: copy collections within the database before applying migrations.
  • Custom: implement MongoBackupStrategy to provide a bespoke backup mechanism (e.g., export to files or another database).

Example configuration snippet:

varmigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()};varstorageOptions=newMongoStorageOptions{MigrationOptions=migrationOptions,InvisibilityTimeout=TimeSpan.FromMinutes(30)};GlobalConfiguration.Configuration.UseMongoStorage("<connection string with database name>",storageOptions);

Naming conventions

Hangfire.Mongo enforces PascalCase for its internal collections and will ignore application-wide convention packs (such as CamelCaseElementNameConvention) for Hangfire collections. This ensures schema stability across applications using different conventions.

Features summary

  • Durable job and state storage in MongoDB.
  • Multiple queue notification strategies: change streams (Watch), polling (Poll), and tailable notifications (TailNotificationsCollection).
  • Schema migration and configurable backup strategies.
  • Pluggable MongoFactory for customizing collections, indexes and serializers.
  • Swappable UTC date/time strategies for fine-grained date handling.
  • Configurable collection prefixing and connection checks.
  • Compatible with MongoDB and MongoDB-compatible services (including Cosmos DB using the MongoDB API).

Contributing

Contributions are welcome. When submitting changes:

  • Add tests for new behavior (if applicable).
  • Document breaking changes and migration steps.
  • Include migration/backup code when modifying schema.

Contributors

License

Hangfire.Mongo is released under the MIT License. See the LICENSE file for details.

About

Mongo DB support for Hangfire

Resources

Stars

281 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - gottscj/Hangfire.Mongo: Mongo DB support for Hangfire · GitHub
Skip to content

Latest commit

History

458 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Hangfire.Mongo

BuildNuGet downloadsLicense

A MongoDB storage provider for Hangfire. Use MongoDB-compatible servers (including Azure Cosmos DB configured with the MongoDB API, and AWS DocumentDB) to persist and process Hangfire jobs.

Why Hangfire.Mongo?

  • Reliable job storage and state management in MongoDB.
  • Multiple queue notification strategies (change streams, tailable collections, polling).
  • Schema migration and backup strategies with configurable behavior.
  • Extension points to customize collection creation, serialization and UTC handling.
  • Works with ASP.NET Core and console-hosted Hangfire servers.

Prerequisites

  • .NET Standard / .NET Core compatible runtime used by your application.
  • MongoDB server (community, Atlas, or other compatible servers). For Cosmos DB use the MongoDB API endpoint.

Hangfire (project and docs)

Installation

Install from NuGet (recommended):

dotnet add package Hangfire.Mongo

Or via the Package Manager Console in Visual Studio:

PM> Install-Package Hangfire.Mongo

Quick start — ASP.NET Core

Add Hangfire and Hangfire.Mongo in your Startup/Program configuration:

// Program.cs or Startup.csvarmongoUrl=newMongoUrl("mongodb://localhost:27017/jobs");varmongoClient=newMongoClient(mongoUrl.ToMongoUrl());services.AddHangfire(configuration =>configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseMongoStorage(mongoClient,mongoUrl.DatabaseName,newMongoStorageOptions{Prefix="hangfire.mongo",CheckConnection=true,MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}}));services.AddHangfireServer();

Quick start — Console

varoptions=newMongoStorageOptions{MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newDropMongoMigrationStrategy(),BackupStrategy=newNoneMongoBackupStrategy()}};usingvarstorage=newMongoStorage(MongoClientSettings.FromConnectionString("mongodb://localhost:27017"),"jobs",options);usingvarserver=newBackgroundJobServer(storage);

Configuration highlights

  • Prefix: prefix for Hangfire collection names (default: no prefix).
  • CheckConnection: verify connectivity at startup (recommended for production).
  • InvisibilityTimeout: controls how long a job remains in Processing before becoming visible again; configure to avoid stuck jobs.
  • CheckQueuedJobsStrategy: choose between Watch (change streams), Poll, or TailNotificationsCollection.

Cosmos DB (MongoDB API) — Getting started

Hangfire.Mongo works with Azure Cosmos DB only when the Cosmos account is configured to use the MongoDB API. The SQL API is not compatible with the MongoDB driver and therefore not supported.

Important: this project includes a specialized options type, CosmosStorageOptions (in Hangfire.Mongo.CosmosDB), which adjusts a number of settings that are required or recommended for Cosmos DB. Use CosmosStorageOptions instead of MongoStorageOptions when targeting Cosmos DB.

Key overrides in CosmosStorageOptions

  • CheckQueuedJobsStrategy = Poll
    • Cosmos DB does not reliably support change streams or tailable capped collections in the same way as a regular MongoDB server; polling is the safe strategy.
  • CheckConnection = false
    • Cosmos DB's connection semantics and the way it handles metadata can make the generic startup connection check unsuitable; the Cosmos-specific options disable the default connection ping.
  • SupportsCappedCollection = false
    • Cosmos DB (Mongo API) does not support capped collections — tailing a notifications collection is not available.
  • MigrationLockTimeout = 2 minutes
    • Increased timeout to accommodate Cosmos DB's operational latencies.
  • Factory = new CosmosFactory()
    • A Cosmos-specific factory is used to create storage components tuned for Cosmos behavior.
  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • The UTC date/time strategy is tuned for Cosmos' server responses; this replaces the default set of strategies.

⚠️Note on testing and support

Because access to Azure Cosmos DB (MongoDB API) is limited in the project's test environment, the Cosmos-specific configuration and code paths are not as exhaustively tested as the standard MongoDB implementation. If you use Cosmos DB and encounter issues, please open an issue or submit a PR — community feedback and contributions are appreciated and will help improve compatibility. I will rely on community help to identify and fix provider-specific bugs that cannot be validated in the project's CI/test environment.

Example — recommended Cosmos setup

usingHangfire.Mongo.CosmosDB;varmongoUrl=newMongoUrl("mongodb://<user>:<password>@<your-account>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb");varclient=newMongoClient(mongoUrl.ToMongoUrl());varoptions=newCosmosStorageOptions{// CosmosStorageOptions already sets recommended defaults for Cosmos// You can still tweak other options here if necessary (timeouts, prefix, migration options...)Prefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core pattern: use the Hangfire configuration lambda and call the Cosmos-specific// extension method `UseCosmosStorage` provided in `CosmosBootstrapperConfigurationExtensions`.// This registers the storage with Hangfire and returns the created `CosmosStorage` instance.services.AddHangfire(cfg =>cfg.UseCosmosStorage(client,"<database>",options));services.AddHangfireServer();
// Non-ASP.NET Core / GlobalConfiguration pattern:usingHangfire;usingHangfire.Mongo.CosmosDB;// Register Cosmos storage on the global Hangfire configuration and capture the returned storagevarstorage=GlobalConfiguration.Configuration.UseCosmosStorage(client,"<database>",options);// Create a server that uses the registered storageusingvarserver=newBackgroundJobServer(storage);

Notes:

  • The UseCosmosStorage extension method lives in the Hangfire.Mongo.CosmosDB namespace; add using Hangfire.Mongo.CosmosDB; to access it.
  • The extension wraps construction of CosmosStorage, registers it on the Hangfire global configuration, and returns the created storage instance so you can use it directly when creating a BackgroundJobServer if needed.

Implications and guidance

  • Do not rely on change-stream based notifications or tailable collections with Cosmos — the Poll strategy is used by default in CosmosStorageOptions.
  • CheckConnection is disabled by default for Cosmos; if you enable it you'll need Cosmos-specific checks and longer timeouts (not recommended).
  • Because SupportsCappedCollection is false, TailNotificationsCollection is not a valid CheckQueuedJobsStrategy for Cosmos.
  • CosmosFactory is used to wire Cosmos-specific implementations (e.g., connections, write semantics); if you need to customize behavior, consider subclassing CosmosFactory rather than the base MongoFactory.
  • UTC date/time handling for Cosmos is tuned via IsMasterUtcDateTimeStrategy — if you replace it, ensure any custom strategy matches Cosmos' server response behavior.

DocumentDB (AWS DocumentDB / Mongo-compatible)

This repository provides a DocumentDbStorage path for Mongo-compatible DocumentDB servers (for example AWS DocumentDB). This is intended for MongoDB-compatible services that restrict certain admin commands or have slightly different server responses compared to a full MongoDB server.

⚠️Note on testing and support

DocumentDB-compatible providers (such as AWS DocumentDB) are similarly less well-tested in this project due to limited access to those managed services during development. The DocumentDbStorageOptions and DocumentDB-specific code paths have been designed to be conservative, but if you find bugs or provider-specific issues please report them or contribute fixes — community help is essential for robust support. I will rely on community contributions and reports to discover and resolve provider-specific issues that cannot be exercised in the project's automated tests.

Use DocumentDbStorageOptions (in Hangfire.Mongo.DocumentDB) when targeting DocumentDB-compatible services. The DocumentDbStorageOptions constructor narrows the UTC date/time strategies to use IsMasterUtcDateTimeStrategy, because unprivileged users on these services may not be able to run higher-privileged commands used by other strategies.

Key points about DocumentDbStorageOptions

  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • Restricts date/time probing to the isMaster command which is generally available to unprivileged users on DocumentDB implementations.
  • Other storage options retain the defaults from MongoStorageOptions unless you override them.

How to use

usingHangfire.Mongo.DocumentDB;varclient=newMongoClient("mongodb://<user>:<password>@<your-docdb-host>:27017/?ssl=true");varoptions=newDocumentDbStorageOptions{// You can still customize prefix, migration options, and other MongoStorageOptions membersPrefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core patternservices.AddHangfire(cfg =>cfg.UseDocumentDbStorage(client,"<database>",options));services.AddHangfireServer();// Non-ASP.NET Core / GlobalConfiguration patternvarstorage=GlobalConfiguration.Configuration.UseDocumentDbStorage(client,"<database>",options);usingvarserver=newBackgroundJobServer(storage);

Notes and guidance

  • UseDocumentDbStorage is implemented in DocumentDbBootstrapperConfigurationExtensions (namespace Hangfire.Mongo.DocumentDB). Add using Hangfire.Mongo.DocumentDB; to access it.
  • DocumentDB-compatible services may require TLS/SSL and specific MongoDB driver settings; ensure MongoClientSettings are tuned for your provider (timeouts, retry policy, TLS settings).
  • Because DocumentDbStorageOptions narrows UTC probing to isMaster, it is safer to run with unprivileged users. If you need a different strategy, provide a custom UtcDateTimeStrategy but test carefully against your provider.
  • If your provider exposes additional incompatibilities (capped collections, change streams, etc.), adjust MongoStorageOptions flags (for example SupportsCappedCollection) or use CheckQueuedJobsStrategy = CheckQueuedJobsStrategy.Poll when change-streams/tailable collections are not available.
  • If you need provider-specific creation/wiring logic, consider subclassing the provided DocumentDbStorage or CosmosFactory/MongoFactory patterns as appropriate.

Extending the library

The project provides well-known extension points for advanced customization. Two common extension points are MongoFactory and the UTC date/time strategies.

Note: most classes and methods in this library are public and many are virtual (for example MongoFactory, MongoWriteOnlyTransaction, MongoConnection and related components). This design allows you to subclass and override behaviour at many points — you can swap internal components, change commit behavior, alter notification logic, or plug-in custom serialization by overriding the appropriate virtual methods.

In short: almost all methods are public and many are virtual, so you can change almost any behaviour by subclassing and overriding the provided components.

  1. Overriding MongoFactory

MongoFactory is the place where MongoDB collections, indexes and other components are created. By providing a custom implementation you can:

  • Create custom indexes or collection options,
  • Plug-in custom DTO serialization or mapping,
  • Swap collection implementations for testing.

Accurate examples (based on the real MongoFactory API):

// Example 1: override the database context creation to enforce a custom prefixpublicclassCustomMongoFactory:MongoFactory{publicoverrideHangfireDbContextCreateDbContext(IMongoClientmongoClient,stringdatabaseName,stringprefix){// Force a different prefix for all Hangfire collectionsvarenforcedPrefix="myapp.hangfire";returnbase.CreateDbContext(mongoClient,databaseName,enforcedPrefix);}}
// Example 2: override the distributed lock creation to change resource naming (or add instrumentation)publicclassCustomMongoFactoryWithLocks:MongoFactory{publicoverrideMongoDistributedLockCreateMongoDistributedLock(stringresource,TimeSpantimeout,HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){// Use an application-specific prefix for the lock resource namevarcustomResource=$"MyAppLock:{resource}";// You could also wrap the returned lock with your own implementation that adds logging/metricsreturnnewMongoDistributedLock(customResource,timeout,dbContext,storageOptions);}}

Wiring a custom factory

  • MongoStorageOptions exposes a Factory property. Assign your custom factory before creating MongoStorage or before calling UseMongoStorage:
varoptions=newMongoStorageOptions{Factory=newCustomMongoFactory(),};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

If you need to customize other behaviors (job fetching, notifications, expiration manager etc.), inspect the available virtual methods on MongoFactory and override the appropriate creation method (for example CreateMongoJobFetcher, CreateMongoNotificationObserver, CreateMongoExpirationManager).

  1. Custom UTC date/time strategies

Date/time serialization is important for cross-platform correctness and compatibility with various MongoDB servers. The library exposes swappable UTC strategies (look for implementations under UtcDateTime or similar namespaces) so you can control how DateTime values are serialized and deserialized.

Example custom strategy:

publicclassCustomUtcDateTimeStrategy:UtcDateTimeStrategy{publicoverrideBsonValueSerialize(DateTimedateTime){// Force DateTime to UTC and store as BsonDateTimereturnnewBsonDateTime(DateTime.SpecifyKind(dateTime,DateTimeKind.Utc));}publicoverrideDateTimeDeserialize(BsonValuevalue){returnvalue.AsBsonDateTime.ToUniversalTime();}}

Wiring the strategy

  • Set MongoStorageOptions.UtcDateTimeStrategies to an array of the strategies you want to use (in order of preference). This property is an array of UtcDateTimeStrategy instances and should be configured before creating MongoStorage / calling UseMongoStorage.

Example:

varoptions=newMongoStorageOptions{UtcDateTimeStrategies=newUtcDateTimeStrategy[]{newCustomUtcDateTimeStrategy(),newAggregationUtcDateTimeStrategy(),newServerStatusUtcDateTimeStrategy()}};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));
  • Alternative: if you need lower-level control (for example registering Bson serializers or setting up class maps) you can wire the strategy inside a custom MongoFactory implementation — the factory is invoked when the storage constructs its internal components, so it can be used to ensure serializers and mappings are registered before collections are used.

Example — customize MongoWriteOnlyTransaction

A deeper extension point is MongoWriteOnlyTransaction. You can subclass it to alter commit behavior, add retries, instrumentation or change how notifications are signalled. Below is a compact example that:

  • Subclasses MongoWriteOnlyTransaction and overrides ExecuteCommit to add a retry loop,
  • Supplies the custom transaction from a custom MongoFactory, and
  • Wires the factory via MongoStorageOptions.Factory.
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;usingMongoDB.Bson;usingMongoDB.Driver;usingHangfire.Mongo.Database;// 1) Custom transaction with a simple retry around the bulk commitpublicclassCustomMongoWriteOnlyTransaction:MongoWriteOnlyTransaction{publicCustomMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions):base(dbContext,storageOptions){}protectedoverridevoidExecuteCommit(IMongoCollection<BsonDocument>jobGraph,List<WriteModel<BsonDocument>>writeModels,BulkWriteOptionsbulkWriteOptions){constintmaxAttempts=3;intattempt=0;while(true){try{// use base behavior for actual bulk writebase.ExecuteCommit(jobGraph,writeModels,bulkWriteOptions);return;}catch(MongoException)when(++attempt<maxAttempts){// simple backoff; replace with your preferred retry policy or instrumentationThread.Sleep(200*attempt);}}}}// 2) Custom factory that returns the custom transactionpublicclassCustomMongoFactory:MongoFactory{publicoverrideMongoWriteOnlyTransactionCreateMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){returnnewCustomMongoWriteOnlyTransaction(dbContext,storageOptions);}}// 3) Wiring via optionsvaroptions=newMongoStorageOptions{Factory=newCustomMongoFactory()};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

Notes

  • You can override other virtual methods on MongoWriteOnlyTransaction (for example SignalJobsAddedToQueues or Log) to change notifications or debug output.
  • Use a custom factory when you need to swap multiple internal components; override several Create... methods as needed.

Migration and backups

The library supports migration strategies to handle schema changes between releases. Choose the strategy that fits your operational needs:

  • Throw (default): refuse to start when a schema version mismatch is detected.
  • Drop: drop Hangfire collections and recreate schema from scratch (data loss).
  • Migrate: attempt to migrate data forward. May not preserve all data — test carefully.

Backup strategies

  • None: do not perform backups before migration.
  • Collection clone: copy collections within the database before applying migrations.
  • Custom: implement MongoBackupStrategy to provide a bespoke backup mechanism (e.g., export to files or another database).

Example configuration snippet:

varmigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()};varstorageOptions=newMongoStorageOptions{MigrationOptions=migrationOptions,InvisibilityTimeout=TimeSpan.FromMinutes(30)};GlobalConfiguration.Configuration.UseMongoStorage("<connection string with database name>",storageOptions);

Naming conventions

Hangfire.Mongo enforces PascalCase for its internal collections and will ignore application-wide convention packs (such as CamelCaseElementNameConvention) for Hangfire collections. This ensures schema stability across applications using different conventions.

Features summary

  • Durable job and state storage in MongoDB.
  • Multiple queue notification strategies: change streams (Watch), polling (Poll), and tailable notifications (TailNotificationsCollection).
  • Schema migration and configurable backup strategies.
  • Pluggable MongoFactory for customizing collections, indexes and serializers.
  • Swappable UTC date/time strategies for fine-grained date handling.
  • Configurable collection prefixing and connection checks.
  • Compatible with MongoDB and MongoDB-compatible services (including Cosmos DB using the MongoDB API).

Contributing

Contributions are welcome. When submitting changes:

  • Add tests for new behavior (if applicable).
  • Document breaking changes and migration steps.
  • Include migration/backup code when modifying schema.

Contributors

License

Hangfire.Mongo is released under the MIT License. See the LICENSE file for details.

About

Mongo DB support for Hangfire

Resources

Stars

281 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - gottscj/Hangfire.Mongo: Mongo DB support for Hangfire · GitHub
Skip to content

Latest commit

History

458 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Hangfire.Mongo

BuildNuGet downloadsLicense

A MongoDB storage provider for Hangfire. Use MongoDB-compatible servers (including Azure Cosmos DB configured with the MongoDB API, and AWS DocumentDB) to persist and process Hangfire jobs.

Why Hangfire.Mongo?

  • Reliable job storage and state management in MongoDB.
  • Multiple queue notification strategies (change streams, tailable collections, polling).
  • Schema migration and backup strategies with configurable behavior.
  • Extension points to customize collection creation, serialization and UTC handling.
  • Works with ASP.NET Core and console-hosted Hangfire servers.

Prerequisites

  • .NET Standard / .NET Core compatible runtime used by your application.
  • MongoDB server (community, Atlas, or other compatible servers). For Cosmos DB use the MongoDB API endpoint.

Hangfire (project and docs)

Installation

Install from NuGet (recommended):

dotnet add package Hangfire.Mongo

Or via the Package Manager Console in Visual Studio:

PM> Install-Package Hangfire.Mongo

Quick start — ASP.NET Core

Add Hangfire and Hangfire.Mongo in your Startup/Program configuration:

// Program.cs or Startup.csvarmongoUrl=newMongoUrl("mongodb://localhost:27017/jobs");varmongoClient=newMongoClient(mongoUrl.ToMongoUrl());services.AddHangfire(configuration =>configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseMongoStorage(mongoClient,mongoUrl.DatabaseName,newMongoStorageOptions{Prefix="hangfire.mongo",CheckConnection=true,MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}}));services.AddHangfireServer();

Quick start — Console

varoptions=newMongoStorageOptions{MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newDropMongoMigrationStrategy(),BackupStrategy=newNoneMongoBackupStrategy()}};usingvarstorage=newMongoStorage(MongoClientSettings.FromConnectionString("mongodb://localhost:27017"),"jobs",options);usingvarserver=newBackgroundJobServer(storage);

Configuration highlights

  • Prefix: prefix for Hangfire collection names (default: no prefix).
  • CheckConnection: verify connectivity at startup (recommended for production).
  • InvisibilityTimeout: controls how long a job remains in Processing before becoming visible again; configure to avoid stuck jobs.
  • CheckQueuedJobsStrategy: choose between Watch (change streams), Poll, or TailNotificationsCollection.

Cosmos DB (MongoDB API) — Getting started

Hangfire.Mongo works with Azure Cosmos DB only when the Cosmos account is configured to use the MongoDB API. The SQL API is not compatible with the MongoDB driver and therefore not supported.

Important: this project includes a specialized options type, CosmosStorageOptions (in Hangfire.Mongo.CosmosDB), which adjusts a number of settings that are required or recommended for Cosmos DB. Use CosmosStorageOptions instead of MongoStorageOptions when targeting Cosmos DB.

Key overrides in CosmosStorageOptions

  • CheckQueuedJobsStrategy = Poll
    • Cosmos DB does not reliably support change streams or tailable capped collections in the same way as a regular MongoDB server; polling is the safe strategy.
  • CheckConnection = false
    • Cosmos DB's connection semantics and the way it handles metadata can make the generic startup connection check unsuitable; the Cosmos-specific options disable the default connection ping.
  • SupportsCappedCollection = false
    • Cosmos DB (Mongo API) does not support capped collections — tailing a notifications collection is not available.
  • MigrationLockTimeout = 2 minutes
    • Increased timeout to accommodate Cosmos DB's operational latencies.
  • Factory = new CosmosFactory()
    • A Cosmos-specific factory is used to create storage components tuned for Cosmos behavior.
  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • The UTC date/time strategy is tuned for Cosmos' server responses; this replaces the default set of strategies.

⚠️Note on testing and support

Because access to Azure Cosmos DB (MongoDB API) is limited in the project's test environment, the Cosmos-specific configuration and code paths are not as exhaustively tested as the standard MongoDB implementation. If you use Cosmos DB and encounter issues, please open an issue or submit a PR — community feedback and contributions are appreciated and will help improve compatibility. I will rely on community help to identify and fix provider-specific bugs that cannot be validated in the project's CI/test environment.

Example — recommended Cosmos setup

usingHangfire.Mongo.CosmosDB;varmongoUrl=newMongoUrl("mongodb://<user>:<password>@<your-account>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb");varclient=newMongoClient(mongoUrl.ToMongoUrl());varoptions=newCosmosStorageOptions{// CosmosStorageOptions already sets recommended defaults for Cosmos// You can still tweak other options here if necessary (timeouts, prefix, migration options...)Prefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core pattern: use the Hangfire configuration lambda and call the Cosmos-specific// extension method `UseCosmosStorage` provided in `CosmosBootstrapperConfigurationExtensions`.// This registers the storage with Hangfire and returns the created `CosmosStorage` instance.services.AddHangfire(cfg =>cfg.UseCosmosStorage(client,"<database>",options));services.AddHangfireServer();
// Non-ASP.NET Core / GlobalConfiguration pattern:usingHangfire;usingHangfire.Mongo.CosmosDB;// Register Cosmos storage on the global Hangfire configuration and capture the returned storagevarstorage=GlobalConfiguration.Configuration.UseCosmosStorage(client,"<database>",options);// Create a server that uses the registered storageusingvarserver=newBackgroundJobServer(storage);

Notes:

  • The UseCosmosStorage extension method lives in the Hangfire.Mongo.CosmosDB namespace; add using Hangfire.Mongo.CosmosDB; to access it.
  • The extension wraps construction of CosmosStorage, registers it on the Hangfire global configuration, and returns the created storage instance so you can use it directly when creating a BackgroundJobServer if needed.

Implications and guidance

  • Do not rely on change-stream based notifications or tailable collections with Cosmos — the Poll strategy is used by default in CosmosStorageOptions.
  • CheckConnection is disabled by default for Cosmos; if you enable it you'll need Cosmos-specific checks and longer timeouts (not recommended).
  • Because SupportsCappedCollection is false, TailNotificationsCollection is not a valid CheckQueuedJobsStrategy for Cosmos.
  • CosmosFactory is used to wire Cosmos-specific implementations (e.g., connections, write semantics); if you need to customize behavior, consider subclassing CosmosFactory rather than the base MongoFactory.
  • UTC date/time handling for Cosmos is tuned via IsMasterUtcDateTimeStrategy — if you replace it, ensure any custom strategy matches Cosmos' server response behavior.

DocumentDB (AWS DocumentDB / Mongo-compatible)

This repository provides a DocumentDbStorage path for Mongo-compatible DocumentDB servers (for example AWS DocumentDB). This is intended for MongoDB-compatible services that restrict certain admin commands or have slightly different server responses compared to a full MongoDB server.

⚠️Note on testing and support

DocumentDB-compatible providers (such as AWS DocumentDB) are similarly less well-tested in this project due to limited access to those managed services during development. The DocumentDbStorageOptions and DocumentDB-specific code paths have been designed to be conservative, but if you find bugs or provider-specific issues please report them or contribute fixes — community help is essential for robust support. I will rely on community contributions and reports to discover and resolve provider-specific issues that cannot be exercised in the project's automated tests.

Use DocumentDbStorageOptions (in Hangfire.Mongo.DocumentDB) when targeting DocumentDB-compatible services. The DocumentDbStorageOptions constructor narrows the UTC date/time strategies to use IsMasterUtcDateTimeStrategy, because unprivileged users on these services may not be able to run higher-privileged commands used by other strategies.

Key points about DocumentDbStorageOptions

  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • Restricts date/time probing to the isMaster command which is generally available to unprivileged users on DocumentDB implementations.
  • Other storage options retain the defaults from MongoStorageOptions unless you override them.

How to use

usingHangfire.Mongo.DocumentDB;varclient=newMongoClient("mongodb://<user>:<password>@<your-docdb-host>:27017/?ssl=true");varoptions=newDocumentDbStorageOptions{// You can still customize prefix, migration options, and other MongoStorageOptions membersPrefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core patternservices.AddHangfire(cfg =>cfg.UseDocumentDbStorage(client,"<database>",options));services.AddHangfireServer();// Non-ASP.NET Core / GlobalConfiguration patternvarstorage=GlobalConfiguration.Configuration.UseDocumentDbStorage(client,"<database>",options);usingvarserver=newBackgroundJobServer(storage);

Notes and guidance

  • UseDocumentDbStorage is implemented in DocumentDbBootstrapperConfigurationExtensions (namespace Hangfire.Mongo.DocumentDB). Add using Hangfire.Mongo.DocumentDB; to access it.
  • DocumentDB-compatible services may require TLS/SSL and specific MongoDB driver settings; ensure MongoClientSettings are tuned for your provider (timeouts, retry policy, TLS settings).
  • Because DocumentDbStorageOptions narrows UTC probing to isMaster, it is safer to run with unprivileged users. If you need a different strategy, provide a custom UtcDateTimeStrategy but test carefully against your provider.
  • If your provider exposes additional incompatibilities (capped collections, change streams, etc.), adjust MongoStorageOptions flags (for example SupportsCappedCollection) or use CheckQueuedJobsStrategy = CheckQueuedJobsStrategy.Poll when change-streams/tailable collections are not available.
  • If you need provider-specific creation/wiring logic, consider subclassing the provided DocumentDbStorage or CosmosFactory/MongoFactory patterns as appropriate.

Extending the library

The project provides well-known extension points for advanced customization. Two common extension points are MongoFactory and the UTC date/time strategies.

Note: most classes and methods in this library are public and many are virtual (for example MongoFactory, MongoWriteOnlyTransaction, MongoConnection and related components). This design allows you to subclass and override behaviour at many points — you can swap internal components, change commit behavior, alter notification logic, or plug-in custom serialization by overriding the appropriate virtual methods.

In short: almost all methods are public and many are virtual, so you can change almost any behaviour by subclassing and overriding the provided components.

  1. Overriding MongoFactory

MongoFactory is the place where MongoDB collections, indexes and other components are created. By providing a custom implementation you can:

  • Create custom indexes or collection options,
  • Plug-in custom DTO serialization or mapping,
  • Swap collection implementations for testing.

Accurate examples (based on the real MongoFactory API):

// Example 1: override the database context creation to enforce a custom prefixpublicclassCustomMongoFactory:MongoFactory{publicoverrideHangfireDbContextCreateDbContext(IMongoClientmongoClient,stringdatabaseName,stringprefix){// Force a different prefix for all Hangfire collectionsvarenforcedPrefix="myapp.hangfire";returnbase.CreateDbContext(mongoClient,databaseName,enforcedPrefix);}}
// Example 2: override the distributed lock creation to change resource naming (or add instrumentation)publicclassCustomMongoFactoryWithLocks:MongoFactory{publicoverrideMongoDistributedLockCreateMongoDistributedLock(stringresource,TimeSpantimeout,HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){// Use an application-specific prefix for the lock resource namevarcustomResource=$"MyAppLock:{resource}";// You could also wrap the returned lock with your own implementation that adds logging/metricsreturnnewMongoDistributedLock(customResource,timeout,dbContext,storageOptions);}}

Wiring a custom factory

  • MongoStorageOptions exposes a Factory property. Assign your custom factory before creating MongoStorage or before calling UseMongoStorage:
varoptions=newMongoStorageOptions{Factory=newCustomMongoFactory(),};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

If you need to customize other behaviors (job fetching, notifications, expiration manager etc.), inspect the available virtual methods on MongoFactory and override the appropriate creation method (for example CreateMongoJobFetcher, CreateMongoNotificationObserver, CreateMongoExpirationManager).

  1. Custom UTC date/time strategies

Date/time serialization is important for cross-platform correctness and compatibility with various MongoDB servers. The library exposes swappable UTC strategies (look for implementations under UtcDateTime or similar namespaces) so you can control how DateTime values are serialized and deserialized.

Example custom strategy:

publicclassCustomUtcDateTimeStrategy:UtcDateTimeStrategy{publicoverrideBsonValueSerialize(DateTimedateTime){// Force DateTime to UTC and store as BsonDateTimereturnnewBsonDateTime(DateTime.SpecifyKind(dateTime,DateTimeKind.Utc));}publicoverrideDateTimeDeserialize(BsonValuevalue){returnvalue.AsBsonDateTime.ToUniversalTime();}}

Wiring the strategy

  • Set MongoStorageOptions.UtcDateTimeStrategies to an array of the strategies you want to use (in order of preference). This property is an array of UtcDateTimeStrategy instances and should be configured before creating MongoStorage / calling UseMongoStorage.

Example:

varoptions=newMongoStorageOptions{UtcDateTimeStrategies=newUtcDateTimeStrategy[]{newCustomUtcDateTimeStrategy(),newAggregationUtcDateTimeStrategy(),newServerStatusUtcDateTimeStrategy()}};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));
  • Alternative: if you need lower-level control (for example registering Bson serializers or setting up class maps) you can wire the strategy inside a custom MongoFactory implementation — the factory is invoked when the storage constructs its internal components, so it can be used to ensure serializers and mappings are registered before collections are used.

Example — customize MongoWriteOnlyTransaction

A deeper extension point is MongoWriteOnlyTransaction. You can subclass it to alter commit behavior, add retries, instrumentation or change how notifications are signalled. Below is a compact example that:

  • Subclasses MongoWriteOnlyTransaction and overrides ExecuteCommit to add a retry loop,
  • Supplies the custom transaction from a custom MongoFactory, and
  • Wires the factory via MongoStorageOptions.Factory.
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;usingMongoDB.Bson;usingMongoDB.Driver;usingHangfire.Mongo.Database;// 1) Custom transaction with a simple retry around the bulk commitpublicclassCustomMongoWriteOnlyTransaction:MongoWriteOnlyTransaction{publicCustomMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions):base(dbContext,storageOptions){}protectedoverridevoidExecuteCommit(IMongoCollection<BsonDocument>jobGraph,List<WriteModel<BsonDocument>>writeModels,BulkWriteOptionsbulkWriteOptions){constintmaxAttempts=3;intattempt=0;while(true){try{// use base behavior for actual bulk writebase.ExecuteCommit(jobGraph,writeModels,bulkWriteOptions);return;}catch(MongoException)when(++attempt<maxAttempts){// simple backoff; replace with your preferred retry policy or instrumentationThread.Sleep(200*attempt);}}}}// 2) Custom factory that returns the custom transactionpublicclassCustomMongoFactory:MongoFactory{publicoverrideMongoWriteOnlyTransactionCreateMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){returnnewCustomMongoWriteOnlyTransaction(dbContext,storageOptions);}}// 3) Wiring via optionsvaroptions=newMongoStorageOptions{Factory=newCustomMongoFactory()};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

Notes

  • You can override other virtual methods on MongoWriteOnlyTransaction (for example SignalJobsAddedToQueues or Log) to change notifications or debug output.
  • Use a custom factory when you need to swap multiple internal components; override several Create... methods as needed.

Migration and backups

The library supports migration strategies to handle schema changes between releases. Choose the strategy that fits your operational needs:

  • Throw (default): refuse to start when a schema version mismatch is detected.
  • Drop: drop Hangfire collections and recreate schema from scratch (data loss).
  • Migrate: attempt to migrate data forward. May not preserve all data — test carefully.

Backup strategies

  • None: do not perform backups before migration.
  • Collection clone: copy collections within the database before applying migrations.
  • Custom: implement MongoBackupStrategy to provide a bespoke backup mechanism (e.g., export to files or another database).

Example configuration snippet:

varmigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()};varstorageOptions=newMongoStorageOptions{MigrationOptions=migrationOptions,InvisibilityTimeout=TimeSpan.FromMinutes(30)};GlobalConfiguration.Configuration.UseMongoStorage("<connection string with database name>",storageOptions);

Naming conventions

Hangfire.Mongo enforces PascalCase for its internal collections and will ignore application-wide convention packs (such as CamelCaseElementNameConvention) for Hangfire collections. This ensures schema stability across applications using different conventions.

Features summary

  • Durable job and state storage in MongoDB.
  • Multiple queue notification strategies: change streams (Watch), polling (Poll), and tailable notifications (TailNotificationsCollection).
  • Schema migration and configurable backup strategies.
  • Pluggable MongoFactory for customizing collections, indexes and serializers.
  • Swappable UTC date/time strategies for fine-grained date handling.
  • Configurable collection prefixing and connection checks.
  • Compatible with MongoDB and MongoDB-compatible services (including Cosmos DB using the MongoDB API).

Contributing

Contributions are welcome. When submitting changes:

  • Add tests for new behavior (if applicable).
  • Document breaking changes and migration steps.
  • Include migration/backup code when modifying schema.

Contributors

License

Hangfire.Mongo is released under the MIT License. See the LICENSE file for details.

About

Mongo DB support for Hangfire

Resources

Stars

281 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - gottscj/Hangfire.Mongo: Mongo DB support for Hangfire · GitHub
Skip to content

Latest commit

History

458 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Hangfire.Mongo

BuildNuGet downloadsLicense

A MongoDB storage provider for Hangfire. Use MongoDB-compatible servers (including Azure Cosmos DB configured with the MongoDB API, and AWS DocumentDB) to persist and process Hangfire jobs.

Why Hangfire.Mongo?

  • Reliable job storage and state management in MongoDB.
  • Multiple queue notification strategies (change streams, tailable collections, polling).
  • Schema migration and backup strategies with configurable behavior.
  • Extension points to customize collection creation, serialization and UTC handling.
  • Works with ASP.NET Core and console-hosted Hangfire servers.

Prerequisites

  • .NET Standard / .NET Core compatible runtime used by your application.
  • MongoDB server (community, Atlas, or other compatible servers). For Cosmos DB use the MongoDB API endpoint.

Hangfire (project and docs)

Installation

Install from NuGet (recommended):

dotnet add package Hangfire.Mongo

Or via the Package Manager Console in Visual Studio:

PM> Install-Package Hangfire.Mongo

Quick start — ASP.NET Core

Add Hangfire and Hangfire.Mongo in your Startup/Program configuration:

// Program.cs or Startup.csvarmongoUrl=newMongoUrl("mongodb://localhost:27017/jobs");varmongoClient=newMongoClient(mongoUrl.ToMongoUrl());services.AddHangfire(configuration =>configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings().UseMongoStorage(mongoClient,mongoUrl.DatabaseName,newMongoStorageOptions{Prefix="hangfire.mongo",CheckConnection=true,MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}}));services.AddHangfireServer();

Quick start — Console

varoptions=newMongoStorageOptions{MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newDropMongoMigrationStrategy(),BackupStrategy=newNoneMongoBackupStrategy()}};usingvarstorage=newMongoStorage(MongoClientSettings.FromConnectionString("mongodb://localhost:27017"),"jobs",options);usingvarserver=newBackgroundJobServer(storage);

Configuration highlights

  • Prefix: prefix for Hangfire collection names (default: no prefix).
  • CheckConnection: verify connectivity at startup (recommended for production).
  • InvisibilityTimeout: controls how long a job remains in Processing before becoming visible again; configure to avoid stuck jobs.
  • CheckQueuedJobsStrategy: choose between Watch (change streams), Poll, or TailNotificationsCollection.

Cosmos DB (MongoDB API) — Getting started

Hangfire.Mongo works with Azure Cosmos DB only when the Cosmos account is configured to use the MongoDB API. The SQL API is not compatible with the MongoDB driver and therefore not supported.

Important: this project includes a specialized options type, CosmosStorageOptions (in Hangfire.Mongo.CosmosDB), which adjusts a number of settings that are required or recommended for Cosmos DB. Use CosmosStorageOptions instead of MongoStorageOptions when targeting Cosmos DB.

Key overrides in CosmosStorageOptions

  • CheckQueuedJobsStrategy = Poll
    • Cosmos DB does not reliably support change streams or tailable capped collections in the same way as a regular MongoDB server; polling is the safe strategy.
  • CheckConnection = false
    • Cosmos DB's connection semantics and the way it handles metadata can make the generic startup connection check unsuitable; the Cosmos-specific options disable the default connection ping.
  • SupportsCappedCollection = false
    • Cosmos DB (Mongo API) does not support capped collections — tailing a notifications collection is not available.
  • MigrationLockTimeout = 2 minutes
    • Increased timeout to accommodate Cosmos DB's operational latencies.
  • Factory = new CosmosFactory()
    • A Cosmos-specific factory is used to create storage components tuned for Cosmos behavior.
  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • The UTC date/time strategy is tuned for Cosmos' server responses; this replaces the default set of strategies.

⚠️Note on testing and support

Because access to Azure Cosmos DB (MongoDB API) is limited in the project's test environment, the Cosmos-specific configuration and code paths are not as exhaustively tested as the standard MongoDB implementation. If you use Cosmos DB and encounter issues, please open an issue or submit a PR — community feedback and contributions are appreciated and will help improve compatibility. I will rely on community help to identify and fix provider-specific bugs that cannot be validated in the project's CI/test environment.

Example — recommended Cosmos setup

usingHangfire.Mongo.CosmosDB;varmongoUrl=newMongoUrl("mongodb://<user>:<password>@<your-account>.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb");varclient=newMongoClient(mongoUrl.ToMongoUrl());varoptions=newCosmosStorageOptions{// CosmosStorageOptions already sets recommended defaults for Cosmos// You can still tweak other options here if necessary (timeouts, prefix, migration options...)Prefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core pattern: use the Hangfire configuration lambda and call the Cosmos-specific// extension method `UseCosmosStorage` provided in `CosmosBootstrapperConfigurationExtensions`.// This registers the storage with Hangfire and returns the created `CosmosStorage` instance.services.AddHangfire(cfg =>cfg.UseCosmosStorage(client,"<database>",options));services.AddHangfireServer();
// Non-ASP.NET Core / GlobalConfiguration pattern:usingHangfire;usingHangfire.Mongo.CosmosDB;// Register Cosmos storage on the global Hangfire configuration and capture the returned storagevarstorage=GlobalConfiguration.Configuration.UseCosmosStorage(client,"<database>",options);// Create a server that uses the registered storageusingvarserver=newBackgroundJobServer(storage);

Notes:

  • The UseCosmosStorage extension method lives in the Hangfire.Mongo.CosmosDB namespace; add using Hangfire.Mongo.CosmosDB; to access it.
  • The extension wraps construction of CosmosStorage, registers it on the Hangfire global configuration, and returns the created storage instance so you can use it directly when creating a BackgroundJobServer if needed.

Implications and guidance

  • Do not rely on change-stream based notifications or tailable collections with Cosmos — the Poll strategy is used by default in CosmosStorageOptions.
  • CheckConnection is disabled by default for Cosmos; if you enable it you'll need Cosmos-specific checks and longer timeouts (not recommended).
  • Because SupportsCappedCollection is false, TailNotificationsCollection is not a valid CheckQueuedJobsStrategy for Cosmos.
  • CosmosFactory is used to wire Cosmos-specific implementations (e.g., connections, write semantics); if you need to customize behavior, consider subclassing CosmosFactory rather than the base MongoFactory.
  • UTC date/time handling for Cosmos is tuned via IsMasterUtcDateTimeStrategy — if you replace it, ensure any custom strategy matches Cosmos' server response behavior.

DocumentDB (AWS DocumentDB / Mongo-compatible)

This repository provides a DocumentDbStorage path for Mongo-compatible DocumentDB servers (for example AWS DocumentDB). This is intended for MongoDB-compatible services that restrict certain admin commands or have slightly different server responses compared to a full MongoDB server.

⚠️Note on testing and support

DocumentDB-compatible providers (such as AWS DocumentDB) are similarly less well-tested in this project due to limited access to those managed services during development. The DocumentDbStorageOptions and DocumentDB-specific code paths have been designed to be conservative, but if you find bugs or provider-specific issues please report them or contribute fixes — community help is essential for robust support. I will rely on community contributions and reports to discover and resolve provider-specific issues that cannot be exercised in the project's automated tests.

Use DocumentDbStorageOptions (in Hangfire.Mongo.DocumentDB) when targeting DocumentDB-compatible services. The DocumentDbStorageOptions constructor narrows the UTC date/time strategies to use IsMasterUtcDateTimeStrategy, because unprivileged users on these services may not be able to run higher-privileged commands used by other strategies.

Key points about DocumentDbStorageOptions

  • UtcDateTimeStrategies = [ new IsMasterUtcDateTimeStrategy() ]
    • Restricts date/time probing to the isMaster command which is generally available to unprivileged users on DocumentDB implementations.
  • Other storage options retain the defaults from MongoStorageOptions unless you override them.

How to use

usingHangfire.Mongo.DocumentDB;varclient=newMongoClient("mongodb://<user>:<password>@<your-docdb-host>:27017/?ssl=true");varoptions=newDocumentDbStorageOptions{// You can still customize prefix, migration options, and other MongoStorageOptions membersPrefix="hangfire",MigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()}};// ASP.NET Core patternservices.AddHangfire(cfg =>cfg.UseDocumentDbStorage(client,"<database>",options));services.AddHangfireServer();// Non-ASP.NET Core / GlobalConfiguration patternvarstorage=GlobalConfiguration.Configuration.UseDocumentDbStorage(client,"<database>",options);usingvarserver=newBackgroundJobServer(storage);

Notes and guidance

  • UseDocumentDbStorage is implemented in DocumentDbBootstrapperConfigurationExtensions (namespace Hangfire.Mongo.DocumentDB). Add using Hangfire.Mongo.DocumentDB; to access it.
  • DocumentDB-compatible services may require TLS/SSL and specific MongoDB driver settings; ensure MongoClientSettings are tuned for your provider (timeouts, retry policy, TLS settings).
  • Because DocumentDbStorageOptions narrows UTC probing to isMaster, it is safer to run with unprivileged users. If you need a different strategy, provide a custom UtcDateTimeStrategy but test carefully against your provider.
  • If your provider exposes additional incompatibilities (capped collections, change streams, etc.), adjust MongoStorageOptions flags (for example SupportsCappedCollection) or use CheckQueuedJobsStrategy = CheckQueuedJobsStrategy.Poll when change-streams/tailable collections are not available.
  • If you need provider-specific creation/wiring logic, consider subclassing the provided DocumentDbStorage or CosmosFactory/MongoFactory patterns as appropriate.

Extending the library

The project provides well-known extension points for advanced customization. Two common extension points are MongoFactory and the UTC date/time strategies.

Note: most classes and methods in this library are public and many are virtual (for example MongoFactory, MongoWriteOnlyTransaction, MongoConnection and related components). This design allows you to subclass and override behaviour at many points — you can swap internal components, change commit behavior, alter notification logic, or plug-in custom serialization by overriding the appropriate virtual methods.

In short: almost all methods are public and many are virtual, so you can change almost any behaviour by subclassing and overriding the provided components.

  1. Overriding MongoFactory

MongoFactory is the place where MongoDB collections, indexes and other components are created. By providing a custom implementation you can:

  • Create custom indexes or collection options,
  • Plug-in custom DTO serialization or mapping,
  • Swap collection implementations for testing.

Accurate examples (based on the real MongoFactory API):

// Example 1: override the database context creation to enforce a custom prefixpublicclassCustomMongoFactory:MongoFactory{publicoverrideHangfireDbContextCreateDbContext(IMongoClientmongoClient,stringdatabaseName,stringprefix){// Force a different prefix for all Hangfire collectionsvarenforcedPrefix="myapp.hangfire";returnbase.CreateDbContext(mongoClient,databaseName,enforcedPrefix);}}
// Example 2: override the distributed lock creation to change resource naming (or add instrumentation)publicclassCustomMongoFactoryWithLocks:MongoFactory{publicoverrideMongoDistributedLockCreateMongoDistributedLock(stringresource,TimeSpantimeout,HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){// Use an application-specific prefix for the lock resource namevarcustomResource=$"MyAppLock:{resource}";// You could also wrap the returned lock with your own implementation that adds logging/metricsreturnnewMongoDistributedLock(customResource,timeout,dbContext,storageOptions);}}

Wiring a custom factory

  • MongoStorageOptions exposes a Factory property. Assign your custom factory before creating MongoStorage or before calling UseMongoStorage:
varoptions=newMongoStorageOptions{Factory=newCustomMongoFactory(),};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

If you need to customize other behaviors (job fetching, notifications, expiration manager etc.), inspect the available virtual methods on MongoFactory and override the appropriate creation method (for example CreateMongoJobFetcher, CreateMongoNotificationObserver, CreateMongoExpirationManager).

  1. Custom UTC date/time strategies

Date/time serialization is important for cross-platform correctness and compatibility with various MongoDB servers. The library exposes swappable UTC strategies (look for implementations under UtcDateTime or similar namespaces) so you can control how DateTime values are serialized and deserialized.

Example custom strategy:

publicclassCustomUtcDateTimeStrategy:UtcDateTimeStrategy{publicoverrideBsonValueSerialize(DateTimedateTime){// Force DateTime to UTC and store as BsonDateTimereturnnewBsonDateTime(DateTime.SpecifyKind(dateTime,DateTimeKind.Utc));}publicoverrideDateTimeDeserialize(BsonValuevalue){returnvalue.AsBsonDateTime.ToUniversalTime();}}

Wiring the strategy

  • Set MongoStorageOptions.UtcDateTimeStrategies to an array of the strategies you want to use (in order of preference). This property is an array of UtcDateTimeStrategy instances and should be configured before creating MongoStorage / calling UseMongoStorage.

Example:

varoptions=newMongoStorageOptions{UtcDateTimeStrategies=newUtcDateTimeStrategy[]{newCustomUtcDateTimeStrategy(),newAggregationUtcDateTimeStrategy(),newServerStatusUtcDateTimeStrategy()}};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));
  • Alternative: if you need lower-level control (for example registering Bson serializers or setting up class maps) you can wire the strategy inside a custom MongoFactory implementation — the factory is invoked when the storage constructs its internal components, so it can be used to ensure serializers and mappings are registered before collections are used.

Example — customize MongoWriteOnlyTransaction

A deeper extension point is MongoWriteOnlyTransaction. You can subclass it to alter commit behavior, add retries, instrumentation or change how notifications are signalled. Below is a compact example that:

  • Subclasses MongoWriteOnlyTransaction and overrides ExecuteCommit to add a retry loop,
  • Supplies the custom transaction from a custom MongoFactory, and
  • Wires the factory via MongoStorageOptions.Factory.
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading;usingMongoDB.Bson;usingMongoDB.Driver;usingHangfire.Mongo.Database;// 1) Custom transaction with a simple retry around the bulk commitpublicclassCustomMongoWriteOnlyTransaction:MongoWriteOnlyTransaction{publicCustomMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions):base(dbContext,storageOptions){}protectedoverridevoidExecuteCommit(IMongoCollection<BsonDocument>jobGraph,List<WriteModel<BsonDocument>>writeModels,BulkWriteOptionsbulkWriteOptions){constintmaxAttempts=3;intattempt=0;while(true){try{// use base behavior for actual bulk writebase.ExecuteCommit(jobGraph,writeModels,bulkWriteOptions);return;}catch(MongoException)when(++attempt<maxAttempts){// simple backoff; replace with your preferred retry policy or instrumentationThread.Sleep(200*attempt);}}}}// 2) Custom factory that returns the custom transactionpublicclassCustomMongoFactory:MongoFactory{publicoverrideMongoWriteOnlyTransactionCreateMongoWriteOnlyTransaction(HangfireDbContextdbContext,MongoStorageOptionsstorageOptions){returnnewCustomMongoWriteOnlyTransaction(dbContext,storageOptions);}}// 3) Wiring via optionsvaroptions=newMongoStorageOptions{Factory=newCustomMongoFactory()};services.AddHangfire(cfg =>cfg.UseMongoStorage(mongoClient,"mydb",options));

Notes

  • You can override other virtual methods on MongoWriteOnlyTransaction (for example SignalJobsAddedToQueues or Log) to change notifications or debug output.
  • Use a custom factory when you need to swap multiple internal components; override several Create... methods as needed.

Migration and backups

The library supports migration strategies to handle schema changes between releases. Choose the strategy that fits your operational needs:

  • Throw (default): refuse to start when a schema version mismatch is detected.
  • Drop: drop Hangfire collections and recreate schema from scratch (data loss).
  • Migrate: attempt to migrate data forward. May not preserve all data — test carefully.

Backup strategies

  • None: do not perform backups before migration.
  • Collection clone: copy collections within the database before applying migrations.
  • Custom: implement MongoBackupStrategy to provide a bespoke backup mechanism (e.g., export to files or another database).

Example configuration snippet:

varmigrationOptions=newMongoMigrationOptions{MigrationStrategy=newMigrateMongoMigrationStrategy(),BackupStrategy=newCollectionMongoBackupStrategy()};varstorageOptions=newMongoStorageOptions{MigrationOptions=migrationOptions,InvisibilityTimeout=TimeSpan.FromMinutes(30)};GlobalConfiguration.Configuration.UseMongoStorage("<connection string with database name>",storageOptions);

Naming conventions

Hangfire.Mongo enforces PascalCase for its internal collections and will ignore application-wide convention packs (such as CamelCaseElementNameConvention) for Hangfire collections. This ensures schema stability across applications using different conventions.

Features summary

  • Durable job and state storage in MongoDB.
  • Multiple queue notification strategies: change streams (Watch), polling (Poll), and tailable notifications (TailNotificationsCollection).
  • Schema migration and configurable backup strategies.
  • Pluggable MongoFactory for customizing collections, indexes and serializers.
  • Swappable UTC date/time strategies for fine-grained date handling.
  • Configurable collection prefixing and connection checks.
  • Compatible with MongoDB and MongoDB-compatible services (including Cosmos DB using the MongoDB API).

Contributing

Contributions are welcome. When submitting changes:

  • Add tests for new behavior (if applicable).
  • Document breaking changes and migration steps.
  • Include migration/backup code when modifying schema.

Contributors

License

Hangfire.Mongo is released under the MIT License. See the LICENSE file for details.

About

Mongo DB support for Hangfire

Resources

Stars

281 stars

Watchers

8 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages