Pilgaard.BackgroundJobs
Pilgaard.BackgroundJobs copied to clipboard
A dotnet library for running background jobs in a scalable and performant manner. The jobs can trigger based on cron expressions, intervals or absolute datetime.

Features
- Implement background jobs through interfaces
- Centralized host to manage and run jobs, keeping memory and thread usage low.
- Dependency Injection support
- Read and update job schedules at runtime through
IConfigurationorIOptionsMonitor - Monitoring jobs using logs and metrics, both compatible with OpenTelemetry
Scheduling Methods
- Cron expressions using
ICronJob - Recurringly at a set interval using
IRecurringJob - Recurringly at a set interval after an initial delay using
IRecurringJobWithInitialDelay - Once at an absolute time using
IOneTimeJob
Use Case examples
- Sending emails
- Processing data
- Enforcing data retention
Getting Started
Make BackgroundJobs by implementing one of these interfaces:
public class CronJob : ICronJob
{
public Task RunJobAsync(CancellationToken cancellationToken = default)
{
Console.WriteLine("Time to backup your databases!");
return Task.CompletedTask;
}
public CronExpression CronExpression => CronExpression.Parse("0 3 * * *");
}
public class RecurringJob : IRecurringJob
{
public Task RunJobAsync(CancellationToken cancellationToken = default)
{
Console.WriteLine("This is your hourly reminder to stay hydrated.");
return Task.CompletedTask;
}
public TimeSpan Interval => TimeSpan.FromHours(1);
}
public class RecurringJobWithInitialDelay : IRecurringJobWithInitialDelay
{
public Task RunJobAsync(CancellationToken cancellationToken = default)
{
Console.WriteLine("This is your hourly reminder to stay hydrated.");
return Task.CompletedTask;
}
public TimeSpan Interval => TimeSpan.FromHours(1);
public TimeSpan InitialDelay => TimeSpan.Zero;
}
public class OneTimeJob : IOneTimeJob
{
public Task RunJobAsync(CancellationToken cancellationToken = default)
{
Console.WriteLine("Happy New Year!");
return Task.CompletedTask;
}
public DateTime ScheduledTimeUtc => new(year: 2023, month: 12, day: 31, hour: 23, minute: 59, second: 59);
}
Registration
Call AddBackgroundJobs() on an IServiceCollection, and then add jobs:
builder.Services.AddBackgroundJobs()
.AddJob<CronJob>()
.AddJob<RecurringJob>()
.AddJob<RecurringJobWithInitialDelay>()
.AddJob<OneTimeJob>();
You can also register jobs in-line for simple use cases:
builder.Services.AddBackgroundJobs()
.AddJob(
name: "basic-cronjob",
job: () => {},
cronExpression: CronExpression.Parse("* * * * *"))
.AddJob(
name: "basic-recurringjob",
job: () => {},
interval: TimeSpan.FromSeconds(3))
.AddJob(
name: "basic-recurringjob-withinitialdelay",
job: () => {},
interval: TimeSpan.FromSeconds(3),
initialDelay: TimeSpan.Zero)
.AddJob(
name: "basic-onetimejob",
job: () => {},
scheduledTimeUtc: DateTime.UtcNow.AddHours(1))
.AddAsyncJob(
name: "async-cronjob",
job: cancellationToken => Task.CompletedTask,
cronExpression: CronExpression.Parse("* * * * *"))
.AddAsyncJob(
name: "async-recurringjob",
job: cancellationToken => Task.CompletedTask,
interval: TimeSpan.FromSeconds(3))
.AddAsyncJob(
name: "async-recurringjob-withinitialdelay",
job: cancellationToken => Task.CompletedTask,
interval: TimeSpan.FromSeconds(3),
initialDelay: TimeSpan.Zero)
.AddAsyncJob(
name: "async-onetimejob",
job: cancellationToken => Task.CompletedTask,
scheduledTimeUtc: DateTime.UtcNow.AddHours(1));
Samples
| Sample 🔗 | Tags |
|---|---|
| BackgroundJobs.Configuration | ASP.NET, Reloading, Configuration |
| BackgroundJobs.MinimalAPI | ASP.NET, MinimalAPI |
| BackgroundJobs.OpenTelemetry | ASP.NET, Open Telemetry, Metrics, Logs |
| BackgroundJobs.WorkerService | Console, Worker Service |
Open Telemetry Compatibility
Each project exposes histogram metrics, which allow monitoring the duration and count of jobs.
The meter names match the project names.
The Open Telemetry Sample shows how to collect CronJob metrics using the Prometheus Open Telemetry exporter.
Roadmap
- ~~Replace Assembly Scanning with registration similar to that of HealthChecks~~
- A separate UI project to help visualize when jobs trigger
- Utilize dotnet 8's new TimeProvider instead of
DateTime.UtcNow - More samples
- Using Blazor Server
- ~~Using a Worker Service~~
- Using IConfiguration to reload job schedule
- Using OneTimeJobs to control feature flags
- Using RecurringJobs to manage data retention
Thanks to
- The developers of Cronos for their excellent Cron expression library.
- JetBrains for providing me with a free license to their products, through their Open Source Support program.