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 Select storage during registration. Use in-memory storage for development and tests. Choose a durable provider before production.
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()
.ConfigureStorage(storage => storage.UseInMemory());The injected type is SendWelcomeEmail.Scheduler. The returned JobHandle identifies the saved
job for monitoring and continuations. It does not mean the job has finished.
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, saved schedules and manual runs.
Batches, dependencies, parallel branches and jobs added at runtime.
Durability, worker count and supported features.
Delivery guarantees, dashboard, telemetry and health checks.
Controllable time, captured storage writes and assertions.
Public types, options and companion packages.