Skip to content

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.

License

Notifications You must be signed in to change notification settings

NielsPilgaard/Pilgaard.BackgroundJobs

Repository files navigation

Pilgaard BackgroundJobs Banner

CI Downloads Version

A dotnet library for running background jobs in a scalable and performant manner.

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 IConfiguration or IOptionsMonitor
  • 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.

About

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.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Languages