BackgroundJobs.Diagnostics.Storage.Sqlite
1.0.0
dotnet add package BackgroundJobs.Diagnostics.Storage.Sqlite --version 1.0.0
NuGet\Install-Package BackgroundJobs.Diagnostics.Storage.Sqlite -Version 1.0.0
<PackageReference Include="BackgroundJobs.Diagnostics.Storage.Sqlite" Version="1.0.0" />
<PackageVersion Include="BackgroundJobs.Diagnostics.Storage.Sqlite" Version="1.0.0" />
<PackageReference Include="BackgroundJobs.Diagnostics.Storage.Sqlite" />
paket add BackgroundJobs.Diagnostics.Storage.Sqlite --version 1.0.0
#r "nuget: BackgroundJobs.Diagnostics.Storage.Sqlite, 1.0.0"
#:package BackgroundJobs.Diagnostics.Storage.Sqlite@1.0.0
#addin nuget:?package=BackgroundJobs.Diagnostics.Storage.Sqlite&version=1.0.0
#tool nuget:?package=BackgroundJobs.Diagnostics.Storage.Sqlite&version=1.0.0
BackgroundJobs.Diagnostics
Application Insights for background jobs in .NET.
Deep observability, diagnostics, and a built-in dashboard for your background jobs — execution history, retry & exception intelligence, slow-job detection, health scores, resource profiling, argument redaction, correlation tracking and OpenTelemetry — with durable storage and minimal setup.
builder.Services.AddJobDiagnostics(); // capture pipeline + store
app.UseJobDiagnosticsDashboard(); // dashboard at /job-diagnostics
That's the whole setup. Restart, run a job, and open /job-diagnostics.
Status — early preview (
0.1.0-preview). The core pipeline, durable storage (SQLite / SQL Server / PostgreSQL, or any EF Core provider), the Hangfire and BackgroundService adapters, OpenTelemetry spans and the dashboard are implemented. Alerting, replay, dead-job rules and the Quartz / ABP / broker adapters are on the roadmap. APIs may change before1.0.
Contents
- Why
- Install
- Packages
- Quick start
- Instrumenting jobs
- Dashboard
- Storage
- Configuration
- Security & redaction
- OpenTelemetry
- How it works
- Roadmap
- Building from source
- Contributing
- License
Why
When a background job fails at 3am, most teams have a log line and not much else. BackgroundJobs.Diagnostics answers the questions you actually have — automatically:
| Question | Answer |
|---|---|
| Which jobs failed, and why? | Failed view + exception intelligence (category, failing method, probable cause) |
| How many retries? | Per-attempt retry history |
| What arguments were used? | Captured, redacted argument snapshot |
| How long did it take — and is it degrading? | Duration vs. an online baseline, with slow-job flagging |
| Which request triggered it? | Correlation / trace propagation |
| Is this job healthy? | A 0–100 health score per job |
| Where can I see it all? | A built-in dashboard at /job-diagnostics |
Design priorities: never slow down or break a job, redact sensitive data by default, and install in two lines.
Install
# Everything you need to get started (core + BackgroundService adapter + dashboard)
dotnet add package BackgroundJobs.Diagnostics
# Durable storage (pick one)
dotnet add package BackgroundJobs.Diagnostics.Storage.Sqlite
dotnet add package BackgroundJobs.Diagnostics.Storage.SqlServer
dotnet add package BackgroundJobs.Diagnostics.Storage.PostgreSql
# Hangfire integration
dotnet add package BackgroundJobs.Diagnostics.Hangfire
Preview packages are published as prerelease — enable "include prerelease" in your IDE, or append
--prereleasetodotnet add package.
Packages
| Package | Purpose |
|---|---|
BackgroundJobs.Diagnostics |
Meta-package: Core + BackgroundServices + Dashboard |
BackgroundJobs.Diagnostics.Core |
Framework-agnostic capture pipeline, domain model, in-memory store, redaction, baselines, anomaly + health scoring |
BackgroundJobs.Diagnostics.BackgroundServices |
InstrumentedBackgroundService base + TrackAsync(...) for manual / loop jobs |
BackgroundJobs.Diagnostics.Hangfire |
Hangfire server-filter adapter + worker-health probe |
BackgroundJobs.Diagnostics.Dashboard |
Self-contained web dashboard (no build step, no CDN) |
BackgroundJobs.Diagnostics.Storage.EntityFrameworkCore |
Durable EF Core store (provider-agnostic base) |
BackgroundJobs.Diagnostics.Storage.Sqlite |
SQLite storage provider |
BackgroundJobs.Diagnostics.Storage.SqlServer |
SQL Server storage provider |
BackgroundJobs.Diagnostics.Storage.PostgreSql |
PostgreSQL storage provider (Npgsql) |
Quick start
using BackgroundJobs.Diagnostics.Core.DependencyInjection;
using BackgroundJobs.Diagnostics.Core.Options;
using BackgroundJobs.Diagnostics.BackgroundServices;
using BackgroundJobs.Diagnostics.Dashboard;
using BackgroundJobs.Diagnostics.Storage.Sqlite;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddJobDiagnostics(options =>
{
options.ServiceName = "billing-api";
options.Capture.Arguments = ArgumentCaptureMode.Sampled; // 10% sampled by default
options.Security.RedactProperties("password", "ssn"); // on top of safe defaults
})
.UseSqlite("Data Source=jobdiagnostics.db") // durable storage
.AddBackgroundServices();
var app = builder.Build();
app.UseJobDiagnosticsDashboard(); // → /job-diagnostics
app.Run();
Instrumenting jobs
A recurring BackgroundService
Derive from InstrumentedBackgroundService and every tick is captured automatically (duration,
exceptions, profiling, health). Throwing records a failure without killing the loop.
public sealed class CreateInvoiceJob(IJobDiagnostics diag) : InstrumentedBackgroundService(diag)
{
protected override TimeSpan Interval => TimeSpan.FromMinutes(1);
protected override async Task RunAsync(IJobExecutionScope scope, CancellationToken ct)
{
scope.AddTimelineEvent("Loading customer", TimelineEventKind.Custom);
await DoWorkAsync(ct);
}
}
// Program.cs
builder.Services.AddHostedService<CreateInvoiceJob>();
Any unit of work
Wrap an arbitrary operation with TrackAsync — useful inside an existing IHostedService,
a message consumer, or a one-off task.
await diagnostics.TrackAsync("ReconcileLedger", async scope =>
{
scope.AddDependency(new DependencyCall { System = "SqlServer", Type = DependencyType.Sql });
await ledger.ReconcileAsync();
});
Hangfire
builder.Services.AddJobDiagnostics().AddHangfire();
builder.Services.AddHangfire((sp, config) => config
.UseSqlServerStorage(connectionString)
.UseJobDiagnostics(sp)); // attaches the diagnostics server filter
Hangfire job lifecycle, retry counts, arguments, correlation and server (worker) health are captured automatically.
Dashboard
app.UseJobDiagnosticsDashboard() mounts a self-contained UI at /job-diagnostics — no build
step, no CDN, no external assets:
- Overview — throughput, success rate, p95 duration, failures and worker health
- Running / All executions / Failed / Slow / Retried — searchable, paginated tables
- Incidents and Workers
- Execution detail — arguments (redacted), exception intelligence, timeline, dependencies, resource profile
- Light / dark theme and selectable time range
app.UseJobDiagnosticsDashboard(options =>
{
options.BasePath = "/admin/jobs";
options.AuthorizationPolicy = "JobDiagnosticsAdmin"; // require a policy
options.ReadOnly = true;
});
Security: in
Productionthe dashboard fails closed — it is inaccessible unless you set anAuthorizationPolicy. In Development it is open for convenience.
Storage
The default store is in-memory (great for development; data is lost on restart). For durable storage, add a provider package and select it on the builder:
builder.Services.AddJobDiagnostics()
.UseSqlite("Data Source=jobdiagnostics.db")
// .UseSqlServer("Server=...;Database=Diagnostics;Trusted_Connection=True;TrustServerCertificate=True")
// .UsePostgreSql("Host=localhost;Database=diagnostics;Username=postgres;Password=...")
.AddBackgroundServices();
Any other EF Core provider (MySQL, Oracle, …) works through the generic hook:
builder.Services.AddJobDiagnostics()
.UseEntityFrameworkCore(db => db.UseOracle(connectionString))
.AddBackgroundServices();
The schema is created on first run. To manage it yourself (migrations / DBA script), disable it:
.UseSqlite(conn, o => o.AutoCreateSchema = false)
Configuration
All options are set via AddJobDiagnostics(options => …).
| Option | Default | Description |
|---|---|---|
ServiceName |
"default" |
Logical service name stamped on records and spans |
Capture.Arguments |
Sampled |
None · Sampled · Always |
Capture.ArgumentSampleRate |
0.10 |
Fraction of executions that keep arguments |
Capture.MaxArgumentBytes |
16384 |
Size cap for captured arguments |
Capture.Profiling |
OnSlowOrFailed |
Off · OnSlowOrFailed · Sampled · Always |
Capture.Timeline / Capture.Dependencies |
true |
Capture timeline events / dependency calls |
Security.RedactProperties(...) |
safe defaults | Add sensitive property names to mask |
Security.RedactPattern(regex) |
JWT, PAN | Add value patterns to mask |
SlowJob.Sigma |
3 |
Flag if duration > mean + Sigma·σ (with a percentile guard) |
SlowJob.WarmupSamples |
30 |
Samples needed before slow detection activates |
Retention.KeepExecutions |
30 days |
Executions older than this are pruned |
Pipeline.ChannelCapacity |
10000 |
Bounded capture buffer; events drop (never block) when full |
EnableOpenTelemetry |
true |
Emit job-execution spans |
Security & redaction
Background-job arguments often contain PII (emails, tokens, card numbers). Redaction is on by default and runs on a background thread before anything is persisted — sensitive data never reaches the store.
options.Security.RedactProperties("password", "ssn", "authorization", "cardNumber");
options.Security.RedactPattern(@"\b\d{13,19}\b"); // PAN-like numbers
Out of the box it masks common sensitive keys (password, token, secret, apikey,
connectionstring, …) and patterns for JWTs and long digit sequences.
OpenTelemetry
Each execution emits an Activity span on the BackgroundJobs.Diagnostics source. Register it
with your existing OpenTelemetry pipeline to export job traces to Jaeger, Tempo, Zipkin,
Application Insights, or any OTLP backend:
services.AddOpenTelemetry().WithTracing(tracing => tracing
.AddSource("BackgroundJobs.Diagnostics")
.AddOtlpExporter());
It works standalone too — no OpenTelemetry pipeline is required.
How it works
Job thread ──(one non-blocking write)──▶ bounded channel ──▶ background dispatcher ──▶ store
│
redact · baseline · score · exception intel
- Never slows down or breaks a job. The hot path is a single non-blocking write to a bounded channel. Under extreme load, diagnostic events are dropped (and counted) — never jobs. If the store is down, jobs keep running.
- Online baselines. Mean/variance (Welford) and EWMA rates are maintained per job signature, so slow-job detection and health scoring are O(1) and never scan history.
- Pluggable.
IJobDiagnosticsStore,IExceptionAnalyzer,ISlowJobDetector,IHealthScorerandIWorkerProbeare all swappable.
Roadmap
- Alerting (Slack / Teams / email / webhook) with dedup & throttling
- Job replay & snapshots
- Dead-job rules engine and incident grouping
- Automatic SQL / HTTP / Redis dependency capture
- Adapters for Quartz.NET, ABP, and message-broker consumers (RabbitMQ / Kafka / MassTransit)
Building from source
git clone https://github.com/Osama94/BackgroundJobs.Diagnostics.git
cd BackgroundJobs.Diagnostics
dotnet build -c Release
dotnet test -c Release
dotnet run --project samples/SampleApi # → http://localhost:5080/job-diagnostics
Requires the .NET 8 SDK.
Contributing
Issues and pull requests are welcome. Please open an issue to discuss substantial changes before
submitting a PR, and make sure dotnet build and dotnet test pass.
License
MIT © Osama Ahmed
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net8.0
- BackgroundJobs.Diagnostics.Storage.EntityFrameworkCore (>= 1.0.0)
- Microsoft.EntityFrameworkCore.Sqlite (>= 8.0.10)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 115 | 6/10/2026 |
Early preview. Core capture pipeline, durable storage (SQLite/SQL Server/PostgreSQL + any EF Core provider), Hangfire and BackgroundService adapters, OpenTelemetry spans, and a built-in dashboard. APIs may change before 1.0.