Skip to main content
net10.0net8.0net9.0

Blazor component library for ZeroAlloc.Scheduling dashboard.

Published
Oct 15, 2026
3d ago
Total Downloads
9.2K
9,231

Install

dotnet add package ZeroAlloc.Scheduling.Dashboard.Blazor --version 2.2.10
ProductVersions
.NET
net10.0net8.0net9.0

README

ZeroAlloc.Scheduling

NuGet Build License: MIT AOT GitHub Sponsors

ZeroAlloc.Scheduling is a source-generated background job scheduler for .NET 8, 9 and 10. Decorate any class with [Job] and the source generator wires up the executor, DI registration, and recurring startup automatically β€” no reflection, no convention scanning at runtime.

Install

The source generator is bundled into the main package β€” a single PackageReference is all you need:

dotnet add package ZeroAlloc.Scheduling
dotnet add package ZeroAlloc.Scheduling.InMemory   # or EfCore / Orm / Redis

The standalone ZeroAlloc.Scheduling.Generator package is still published for backwards compatibility with existing direct PackageReferences, but new consumers should reference only ZeroAlloc.Scheduling.

Example

using System.Text.Json.Serialization;
using Microsoft.Extensions.DependencyInjection;
using ZeroAlloc.Scheduling;
using ZeroAlloc.Scheduling.InMemory;
using ZeroAlloc.Serialisation;

// 1. Define jobs β€” the generator picks them up automatically.
//    [ZeroAllocSerializable] plus a JsonSerializerContext give each job an AOT-safe serializer,
//    because the store persists every job as bytes.
[Job(Every = Every.Hour)]
[ZeroAllocSerializable(SerializationFormat.SystemTextJson)]
public sealed class CleanupExpiredSessionsJob : IJob
{
    public ValueTask ExecuteAsync(JobContext ctx, CancellationToken ct)
        => ctx.Services.GetRequiredService<ISessionRepository>().DeleteExpiredAsync(ct);
}

[Job]
[ZeroAllocSerializable(SerializationFormat.SystemTextJson)]
public sealed record SendOrderConfirmationJob(int OrderId) : IJob
{
    public ValueTask ExecuteAsync(JobContext ctx, CancellationToken ct)
        => ctx.Services.GetRequiredService<IOrderMailer>().SendConfirmationAsync(OrderId, ct);
}

[JsonSerializable(typeof(CleanupExpiredSessionsJob))]
internal sealed partial class CleanupExpiredSessionsJobJsonContext : JsonSerializerContext;

[JsonSerializable(typeof(SendOrderConfirmationJob))]
internal sealed partial class SendOrderConfirmationJobJsonContext : JsonSerializerContext;

// 2. Register β€” the generated Add...Job() methods wire each executor, and the recurring startup
//    for CleanupExpiredSessionsJob. AddSerializerDispatcher() is generated by ZeroAlloc.Serialisation,
//    which ZeroAlloc.Scheduling brings in; see docs/migrating-to-v2.md.
services.AddSerializerDispatcher();
services.AddScheduling()
        .WithInMemoryStore()
        .AddCleanupExpiredSessionsJob()
        .AddSendOrderConfirmationJob();

// 3. Enqueue a one-off job from application code
public class OrderService(IScheduler scheduler)
{
    public async Task CompleteOrderAsync(Order order, CancellationToken ct)
    {
        await ProcessAsync(order, ct);
        await scheduler.EnqueueAsync(new SendOrderConfirmationJob(order.Id), ct);
    }
}

Performance

Head-to-head vs Coravel 6.0.2 (de-facto in-process scheduler) and a hand-rolled BackgroundService + Timer baseline. BenchmarkDotNet 0.15.8, .NET 10.0.13, measured 2026-10-15. Allocations are exact. Speed is shown as same-run ratios, because the benchmark host is a shared VM; absolute timings are not published.

Operation Coravel Naive Timer ZA.Scheduling
Job registration 696 B per Schedule() call β€” (compile-time) compile-time, 0 B at runtime
Single dispatch (registration only) indistinguishable from an empty method, 0 B indistinguishable from an empty method, 0 B

Honest reading: Coravel's Schedule() is a runtime call that allocates a queue entry; 100 calls allocate 76,320 B and take 15.36Γ— as long as one in the same run. ZA.Scheduling's [Job] registration happens at compile time via source generation β€” no equivalent runtime cost. For dispatch overhead, ZA matches a hand-written Timer: BenchmarkDotNet cannot tell either from an empty method. The value of the abstraction is [Job] itself (declarative retries / cron / store-backed persistence), not raw dispatch speed.

Full methodology + design analysis: docs/performance.md.

Features

  • Source generator β€” [Job] on a class emits a typed executor, DI extension method, and optional recurring startup (IHostedService)
  • Recurring jobs β€” [Job(Cron = "0 * * * *")] or [Job(Every = Every.Hour)] β€” scheduled via Cronos at startup
  • Retry with backoff β€” exponential retry up to MaxAttempts (per-job or global); dead-letters after exhaustion
  • Multiple backends β€” InMemory (dev/test), EF Core (SQL Server / PostgreSQL / SQLite), ZeroAlloc.ORM, Redis
  • Dashboard β€” embedded HTML/JS dashboard via app.MapJobsDashboard("/jobs")
  • Blazor component β€” <JobsDashboard> Razor component for integration into Blazor apps
  • Mediator bridge β€” [Job] + IRequest<Unit> auto-registers MediatorJobTypeExecutor<T>, routing execution through ZeroAlloc.Mediator pipeline behaviors
  • Native AOT compatible β€” no reflection at runtime; all dispatch resolved at compile time

Dashboard

An embedded HTML/JS dashboard β€” summary cards for each job state, a live-refreshing table with per-row requeue / delete actions, and fully responsive down to mobile widths.

app.MapJobsDashboard("/jobs");

// Optional: protect with auth
app.MapJobsDashboard("/jobs").RequireAuthorization("AdminPolicy");

Scheduler dashboard β€” desktop

Tablet (768 Γ— 1024) and mobile (375 Γ— 812) captures live in docs/screenshots/.

See Dashboard for the full endpoint reference and the Blazor component.

Packages

Package Description
ZeroAlloc.Scheduling Core interfaces, worker service, scheduler, bundled source generator
ZeroAlloc.Scheduling.Generator Source generator β€” legacy, already bundled inside ZeroAlloc.Scheduling
ZeroAlloc.Scheduling.InMemory In-process store for development and testing
ZeroAlloc.Scheduling.EfCore EF Core store (SQL Server, PostgreSQL, SQLite)
ZeroAlloc.Scheduling.Orm ZeroAlloc.ORM store (SQLite, PostgreSQL, SQL Server), WithOrm(); net10.0 only
ZeroAlloc.Scheduling.Redis Redis store for distributed deployments
ZeroAlloc.Scheduling.Dashboard Embedded HTML dashboard (MapJobsDashboard)
ZeroAlloc.Scheduling.Dashboard.Blazor Blazor component library
ZeroAlloc.Scheduling.Mediator ZeroAlloc.Mediator bridge
ZeroAlloc.Scheduling.Resilience ZeroAlloc.Resilience bridge: retry, timeout and circuit-breaker around job execution
ZeroAlloc.Scheduling.Telemetry ZeroAlloc.Telemetry bridge: OpenTelemetry spans and metrics for job execution (WithTelemetry())

Documentation

Page Description
Getting Started Install and schedule your first job in five minutes
Source Generator [Job], Every, Cron, generated extension methods
Backends InMemory, EF Core, and Redis store configuration
Dashboard Embedded HTML dashboard and Blazor component
Mediator Bridge Route job execution through ZeroAlloc.Mediator
Resilience Bridge Wrap job execution in ZeroAlloc.Resilience policies
Telemetry Bridge OpenTelemetry spans and metrics for job execution
Migrating to v2 The serializer choice 2.0 made explicit, and the AOT-safe job setup
Diagnostics ZASCH001, ZASCH011, ZASCH012 and ZASCH013 compiler diagnostic reference
Performance Throughput, allocation profile, and tuning guide

License

MIT

Changes from Previous Version

No structural changes between v2.2.9 and v2.2.10.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

Compatibility metadata lists 3 target frameworks; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.