NexJob.Dashboard 0.4.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package NexJob.Dashboard --version 0.4.0
                    
NuGet\Install-Package NexJob.Dashboard -Version 0.4.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NexJob.Dashboard" Version="0.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NexJob.Dashboard" Version="0.4.0" />
                    
Directory.Packages.props
<PackageReference Include="NexJob.Dashboard" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NexJob.Dashboard --version 0.4.0
                    
#r "nuget: NexJob.Dashboard, 0.4.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NexJob.Dashboard@0.4.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NexJob.Dashboard&version=0.4.0
                    
Install as a Cake Addin
#tool nuget:?package=NexJob.Dashboard&version=0.4.0
                    
Install as a Cake Tool

<div align="center">

<br/>

███╗   ██╗███████╗██╗  ██╗     ██╗ ██████╗ ██████╗
████╗  ██║██╔════╝╚██╗██╔╝     ██║██╔═══██╗██╔══██╗
██╔██╗ ██║█████╗   ╚███╔╝      ██║██║   ██║██████╔╝
██║╚██╗██║██╔══╝   ██╔██╗ ██   ██║██║   ██║██╔══██╗
██║ ╚████║███████╗██╔╝ ██╗╚█████╔╝╚██████╔╝██████╔╝
╚═╝  ╚═══╝╚══════╝╚═╝  ╚═╝ ╚════╝  ╚═════╝ ╚═════╝

Background jobs for .NET that stay out of your way.

NuGet NuGet Downloads Build License: MIT .NET

<br/>

</div>


What is NexJob?

NexJob is a modern, open-source background job framework for .NET built for predictable execution, time-sensitive workflows, and explicit failure handling.

Unlike Hangfire — which relies on serialization magic and delayed async — NexJob is async/await native, fully type-safe, and stateless. Jobs run in isolated DI scopes with zero hidden state. Storage is the source of truth. Failures are explicit.


⚡ 30-Second Quick Start

1. Define a job

public class SendInvoiceJob : IJob<SendInvoiceInput>
{
    private readonly IEmailService _email;
    public SendInvoiceJob(IEmailService email) => _email = email;

    public async Task ExecuteAsync(SendInvoiceInput input, CancellationToken ct)
        => await _email.SendAsync(input.Email, "Invoice attached", ct);
}

2. Register

builder.Services.AddNexJob(builder.Configuration)
                .AddNexJobJobs(typeof(Program).Assembly);

3. Enqueue

await scheduler.EnqueueAsync<SendInvoiceJob, SendInvoiceInput>(
    new(orderId, email));

Done. The job executes immediately on an available worker.


🔥 Why NexJob?

Feature Benefit
Predictable execution No serialization magic, no hidden state. Jobs run in isolated DI scopes.
Deadline support (deadlineAfter) Mark jobs expired if not started in time — essential for time-sensitive operations.
Automatic dead-letter handling Failed jobs trigger explicit handlers for alerts, compensation, or cleanup.
Low-latency dispatch Wake-up signaling eliminates polling delay on local enqueue. 2.87× faster than Hangfire.
All storage free PostgreSQL, SQL Server, Redis, MongoDB — no paid adapters or license walls.
Async/await native True async from the ground up. No serialization hacks.
Live config Pause queues, adjust workers, change polling — all at runtime without restart.
Schema migrations Auto-migrations on startup. No manual SQL. No deployment breakage.

⚔️ NexJob vs Hangfire

NexJob Hangfire
License MIT LGPL / paid Pro
Async/await native ❌ serialization-based
Deadline support deadlineAfter
Dead-letter handlers ✅ DI-based
Priority queues
Resource throttling [Throttle]
Per-job retry config [Retry]
Execution windows
Live config
Schema migrations ✅ auto
Graceful shutdown
OpenTelemetry ✅ built-in
Payload versioning IJobMigration
All adapters free ❌ Redis/MongoDB paid
Storage providers 5 (all open-source) 3
Enqueue latency 9.28 μs 26.63 μs

📦 Installation

# Core
dotnet add package NexJob

# Storage (pick one — all free)
dotnet add package NexJob.Postgres
dotnet add package NexJob.SqlServer
dotnet add package NexJob.Redis
dotnet add package NexJob.MongoDB

# Dashboard
dotnet add package NexJob.Dashboard

Features in Depth

Scheduling

Fire and forget

await scheduler.EnqueueAsync<SendInvoiceJob, SendInvoiceInput>(new(orderId, email));

Delayed

await scheduler.ScheduleAsync<SendInvoiceJob, SendInvoiceInput>(
    new(orderId, email), 
    delay: TimeSpan.FromMinutes(5));

Recurring (cron)

await scheduler.RecurringAsync<ReportJob, ReportInput>(
    id: "monthly",
    input: new(DateTime.UtcNow.Month),
    cron: "0 9 1 * *");

Continuations (chaining)

var paymentId = await scheduler.EnqueueAsync<ProcessPaymentJob, PaymentInput>(input);
await scheduler.ContinueWithAsync<SendReceiptJob, ReceiptInput>(paymentId, receiptInput);

Reliability

Global retry policy

By default, jobs retry with exponential backoff. Configure via appsettings.json:

{ "NexJob": { "MaxAttempts": 5 } }

Per-job retry

[Retry(5, InitialDelay = "00:00:30", Multiplier = 2.0, MaxDelay = "01:00:00")]
public class PaymentJob : IJob<PaymentInput> { ... }

Dead-letter handler

Automatically handle jobs that exhaust retries:

public class PaymentDeadLetterHandler : IDeadLetterHandler<PaymentJob>
{
    public async Task HandleAsync(JobRecord failedJob, Exception lastException, CancellationToken ct)
        => await _alerts.SendAsync($"Payment failed", ct);
}

builder.Services.AddTransient<IDeadLetterHandler<PaymentJob>, PaymentDeadLetterHandler>();

Graceful shutdown

Jobs complete naturally on SIGTERM. Strays are requeued by orphan watcher.


Deadlines

Jobs not executed within the deadline are marked Expired and skipped:

await scheduler.EnqueueAsync<PaymentJob, PaymentInput>(
    input,
    deadlineAfter: TimeSpan.FromMinutes(5));

Observability

OpenTelemetry (zero config)

builder.Services.AddOpenTelemetry()
    .WithTracing(t => t.AddSource("NexJob"))
    .WithMetrics(m => m.AddMeter("NexJob"));

Metrics: nexjob.jobs.enqueued, nexjob.jobs.succeeded, nexjob.jobs.failed, nexjob.jobs.expired, nexjob.job.duration.

Job context

public class ImportJob : IJob<ImportInput>
{
    private readonly IJobContext _ctx;
    public ImportJob(IJobContext ctx) => _ctx = ctx;

    public async Task ExecuteAsync(ImportInput input, CancellationToken ct)
    {
        await _ctx.ReportProgressAsync(0, "Starting...", ct);
        // ... do work ...
        await _ctx.ReportProgressAsync(100, "Done.", ct);
    }
}

Job tags

await scheduler.EnqueueAsync<SendInvoiceJob, SendInvoiceInput>(
    input,
    tags: ["tenant:acme", $"invoice:{invoiceId}"]);

var jobs = await scheduler.GetJobsByTagAsync("tenant:acme");

Concurrency & Throttling

Resource throttling

[Throttle(resource: "stripe", maxConcurrent: 3)]
public class ChargeCardJob : IJob<ChargeInput> { ... }

Execution windows

Restrict queues to specific times:

{
  "NexJob": {
    "Queues": [
      {
        "Name": "reports",
        "Workers": 2,
        "ExecutionWindow": {
          "StartTime": "22:00",
          "EndTime": "06:00",
          "TimeZone": "America/Sao_Paulo"
        }
      }
    ]
  }
}

Payload Versioning

Handle evolving job inputs gracefully:

[SchemaVersion(2)]
public class SendInvoiceJob : IJob<SendInvoiceInputV2> { ... }

public class Migration : IJobMigration<SendInvoiceInputV1, SendInvoiceInputV2>
{
    public SendInvoiceInputV2 Migrate(SendInvoiceInputV1 old)
        => new(old.OrderId, old.Email, Language: "en-US");
}

builder.Services.AddJobMigration<SendInvoiceInputV1, SendInvoiceInputV2, Migration>();

Dashboard

Web API:

app.UseNexJobDashboard("/dashboard");

Worker Service / Console App:

services.AddNexJobStandaloneDashboard(configuration);
// Dashboard at http://localhost:5005/dashboard

Configuration

appsettings.json

{
  "NexJob": {
    "Workers": 10,
    "MaxAttempts": 5,
    "PollingInterval": "00:00:05",
    "ShutdownTimeoutSeconds": 30,
    "DefaultQueue": "default",
    "Queues": [
      { "Name": "critical", "Workers": 3 },
      { "Name": "default",  "Workers": 5 }
    ]
  }
}

Code configuration

builder.Services.AddNexJob(builder.Configuration, opt =>
{
    opt.UsePostgres(connectionString);
    opt.Workers = 10;
    opt.MaxAttempts = 5;
});

Storage Providers

All open-source. No license walls.

Package Storage Status
NexJob In-memory Production ready
NexJob.Postgres PostgreSQL 14+ Production ready
NexJob.SqlServer SQL Server 2019+ Production ready
NexJob.Redis Redis 7+ Production ready
NexJob.MongoDB MongoDB 6+ Production ready
NexJob.Oracle Oracle 19c+ Planned

Testing

The in-memory provider is built-in:

services.AddNexJob();  // InMemory by default

Project

Roadmap

v0.4.0  ✅ Wake-up channel · Deadlines · Dead-letter handlers · README updated
v1.0.0  ○ Stable API · production-ready

Contributing

NexJob is open-source. Issues, PRs, and ideas welcome.

git clone git@github.com:oluciano/NexJob.git
cd NexJob && dotnet test

See CONTRIBUTING.md for details.

License

MIT © 2025 Luciano Azevedo


<div align="center"> <br/>

Built with obsession over developer experience.

If Hangfire is the past, NexJob is what comes next.

<br/> </div>

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on NexJob.Dashboard:

Package Downloads
NexJob.Dashboard.Standalone

Standalone dashboard for NexJob — self-hosted monitoring for Worker Services and Console Apps.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.0 104 4/21/2026
3.0.0 109 4/16/2026
2.0.0 107 4/14/2026
1.0.0 94 4/8/2026
0.8.0 90 4/8/2026
0.7.0 96 4/7/2026
0.6.0 95 4/3/2026
0.5.2 95 4/1/2026
0.5.1 96 4/1/2026
0.5.0 98 3/31/2026
0.4.0 91 3/31/2026
0.3.2 112 3/28/2026
0.3.1 130 3/28/2026
0.3.0 97 3/27/2026
0.2.0 99 3/27/2026
0.1.1 96 3/27/2026
0.1.0 89 3/26/2026
0.1.0-alpha 93 3/26/2026