Background Services December 15, 2024 • 4 min read • Patterns

Cron-like scheduling with .NET background workers

By Omarr • Published: December 15, 2024

For many systems, bringing in a full scheduler (Quartz, Hangfire, etc.) is overkill. A simple recurring job runner based on BackgroundService can be enough.

1. Represent schedules in code

I usually start with something simple like “run every N minutes” or “run at a specific hour”, implemented with an interface such as:

public interface IRecurringJob
{
    string Name { get; }
    TimeSpan Interval { get; }
    Task ExecuteAsync(CancellationToken token);
}

The background service then loops over registered jobs and checks if each is due.

2. Avoid drift

If you just await Task.Delay(job.Interval) after each run, execution can drift over time. Instead, record the planned next run and calculate delays based on that.

3. Isolate slow or failing jobs

One slow job shouldn’t block all others. Options:

  • Run each job in its own task with a timeout.
  • Use a small degree-of-parallelism for job execution.
  • Log failures per job, not per scheduler loop.

← Back to all articles