Introduction
Build, schedule and operate source-generated background jobs with Immediate.Handlers.
Immediate.Jobs is a reflection-free background job scheduler built on Immediate.Handlers. A job is an ordinary handler marked
with [Job]; source generation adds a typed scheduler, JSON metadata, an execution adapter and DI
registration. The runtime supplies delayed and recurring work, queues, retries, workflows,
monitoring and durable storage providers.
Immediate.Jobs has not published its first preview packages. These pages intentionally document
the checked-out main implementation and are the one exception to this site’s latest-release
policy. The --prerelease commands below become usable when those packages are published. Preview
APIs and storage schemas can change before a stable release.
Prerequisites and installation
Jobs target net8.0, net9.0, net10.0 and net11.0 and require Immediate.Handlers. Install the
main package in the project that declares the handlers:
dotnet add package Immediate.Jobs --prerelease Choose a durable provider before production; in-memory storage is the automatic default when no provider is selected.
Your first job
using Immediate.Handlers.Shared;
using Immediate.Jobs.Shared;
[Handler, Job(Name = "send-welcome-email", MaxAttempts = 5, Timeout = "00:02:00")]
public sealed partial class SendWelcomeEmail(IEmailSender sender)
{
public sealed record Payload(Guid UserId, string Template);
private ValueTask HandleAsync(Payload payload, CancellationToken cancellationToken) =>
new(sender.SendAsync(payload.UserId, payload.Template, cancellationToken));
}
public sealed class SignupService(SendWelcomeEmail.Scheduler welcomeEmail)
{
public ValueTask<JobHandle> EnqueueAsync(Guid userId, CancellationToken cancellationToken) =>
welcomeEmail.EnqueueAsync(new(userId, "v2"), cancellationToken);
}Register handlers and jobs, then inject the generated scoped scheduler:
builder.Services.AddMyAppHandlers();
builder.Services.AddMyAppJobs(options => options.UseInMemory());The injected type is SendWelcomeEmail.Scheduler. The returned JobHandle is an opaque
identifier for monitoring and continuations—not evidence that the job completed.
A worker can finish a side effect and stop before recording success. The lease then expires and another worker may run the same invocation. Make handlers idempotent: use the job ID or a domain operation ID as a unique key, make updates conditional, and make external APIs idempotent where possible. Immediate.Jobs does not include a transactional outbox.
Where to go next
Declaration rules, payloads, names, retries and timeouts.
Immediate, delayed, absolute and grouped scheduling.
Cron schedules, time zones, reconciliation and manual triggers.
Atomic batches, chains, fan-out/fan-in and dynamic expansion.
Durability, topology and provider capability tradeoffs.
Delivery guarantees, dashboard, telemetry and health checks.
Fake time, deterministic draining, capture-only schedulers and assertions.
Application-facing contracts, options and companion packages.