SqliteStorage.Hangfire
1.1.1
dotnet add package SqliteStorage.Hangfire --version 1.1.1
NuGet\Install-Package SqliteStorage.Hangfire -Version 1.1.1
<PackageReference Include="SqliteStorage.Hangfire" Version="1.1.1" />
<PackageVersion Include="SqliteStorage.Hangfire" Version="1.1.1" />
<PackageReference Include="SqliteStorage.Hangfire" />
paket add SqliteStorage.Hangfire --version 1.1.1
#r "nuget: SqliteStorage.Hangfire, 1.1.1"
#:package SqliteStorage.Hangfire@1.1.1
#addin nuget:?package=SqliteStorage.Hangfire&version=1.1.1
#tool nuget:?package=SqliteStorage.Hangfire&version=1.1.1
SqliteStorage.Hangfire
A lightweight, concurrency-safe SQLite storage for Hangfire, built on Microsoft.Data.Sqlite. No external database server required — point it at a file and go.
The package ships as
SqliteStorage.Hangfirebecause theHangfire.*ID prefix is reserved on nuget.org. The assembly and namespace carry the same name; theUseSqliteStorage()extension lives in theHangfirenamespace for discoverability.
GlobalConfiguration.Configuration.UseSqliteStorage("hangfire.db");
Why another SQLite storage?
The existing community SQLite storage keeps a shared, long-lived connection object that can be
disposed while background timers (heartbeat, distributed lock cleanup, counters aggregator) still
hold a reference to it. Under load — for example when the
Hangfire.Console extension multiplies the
number of storage writes per job — this use-after-dispose race surfaces as a stream of
NullReferenceExceptions from HangfireDbContext, failed heartbeats and broken dashboard pages.
This storage is designed so that failure mode cannot exist:
- No shared connection. Every operation opens a short-lived connection from the Microsoft.Data.Sqlite pool and disposes it when done. There is no shared mutable state to race on.
- WAL mode + busy timeout. Readers never block the writer; write contention is absorbed by SQLite's busy handler plus a retry layer for the stragglers.
- Atomic job fetch. Dequeueing is a single
UPDATE … RETURNINGstatement — no SELECT-then-UPDATE race between workers. - Lease-based distributed locks. A
PRIMARY KEYon the resource makes double-acquisition impossible; leases are extended by a heartbeat and expire on their own if the owner dies. - Crash-safe processing. Fetched jobs send keep-alive updates; if the process dies, the invisibility timeout returns the job to the queue.
- Integer timestamps. All times are stored as Unix epoch milliseconds — no
DateTimestring parsing or timezone surprises.
Works with the dashboard, Hangfire.Console, recurring jobs, delayed jobs, retries, batches of
parallel workers and multiple processes sharing the same database file.
Installation
dotnet add package SqliteStorage.Hangfire
Usage
ASP.NET Core
builder.Services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqliteStorage("hangfire.db"));
builder.Services.AddHangfireServer();
You can pass either a plain file path or a full Microsoft.Data.Sqlite connection string:
.UseSqliteStorage("Data Source=C:\\data\\hangfire.db")
Options
.UseSqliteStorage("hangfire.db", new SqliteStorageOptions
{
QueuePollInterval = TimeSpan.FromSeconds(5), // cross-process polling fallback
InvisibilityTimeout = TimeSpan.FromMinutes(30), // re-queue window after a hard crash
DistributedLockLifetime = TimeSpan.FromSeconds(30), // lock lease length
JobExpirationCheckInterval = TimeSpan.FromMinutes(30),
CountersAggregateInterval = TimeSpan.FromMinutes(5),
BusyTimeout = TimeSpan.FromSeconds(15)
})
In-process enqueues wake waiting workers immediately; QueuePollInterval only matters for jobs
enqueued by other processes sharing the database file.
When to use this (and when not to)
SQLite is a single-file, single-writer database. This storage is a great fit for:
- single-server applications, Windows services, desktop apps and IoT deployments;
- small-to-medium workloads where installing PostgreSQL/SQL Server/Redis is not justified;
- development and integration testing.
It is not a fit for multi-machine clusters — SQLite files should not be shared over network storage. If you outgrow a single machine, switch to one of the client-server storages; the Hangfire API stays the same.
Project layout
src/SqliteStorage.Hangfire— the storage library (netstandard2.0+net8.0)tests/SqliteStorage.Hangfire.Tests— unit tests plus an end-to-end test that runs a realBackgroundJobServerwithHangfire.Consoleunder parallel loadsamples/WebSample— ASP.NET Core sample with the dashboard, console output, recurring and delayed jobs
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Hangfire.Core (>= 1.8.23)
- Microsoft.Data.Sqlite (>= 9.0.17)
- Newtonsoft.Json (>= 13.0.4)
- SQLitePCLRaw.bundle_e_sqlite3 (>= 3.0.3)
-
net8.0
- Hangfire.Core (>= 1.8.23)
- Microsoft.Data.Sqlite (>= 9.0.17)
- Newtonsoft.Json (>= 13.0.4)
- SQLitePCLRaw.bundle_e_sqlite3 (>= 3.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.