- Published on
- 🍵 2 min read
Background Jobs in .NET
- Authors
- Name
- Emin Vergil
- @eminvergil
Overview
- What are Background Jobs?
- Why Use Background Jobs?
- How to Implement Background Jobs in .NET
- A Simple Example
- Cron job example using IHostedService
What are Background Jobs?
Background jobs are tasks that run "behind the scenes" in your application. They handle work that doesn't need to happen immediately or that might take a long time to complete.
Why Use Background Jobs?
- Better Performance: Your app stays fast because heavy tasks run separately.
- Improved User Experience: Users don't have to wait for long tasks to finish.
- Reliability: If a background job fails, it doesn't crash your whole application.
How to Implement Background Jobs in .NET
.NET offers several ways to create background jobs:
- IHostedService
- BackgroundService
- Hangfire
A Simple Example
Here's a basic example using BackgroundService
:
public class MyBackgroundJob : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Do some work here
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}
}
This job will run every 5 minutes until the application shuts down.
Cron job example using IHostedService
public abstract class CronJobService : IHostedService, IDisposable
{
private System.Timers.Timer _timer;
private readonly CronExpression _expression;
private readonly TimeZoneInfo _timeZoneInfo;
protected CronJobService(string cronExpression, TimeZoneInfo timeZoneInfo)
{
_expression = CronExpression.Parse(cronExpression);
_timeZoneInfo = timeZoneInfo;
}
public virtual async Task StartAsync(CancellationToken cancellationToken)
{
await ScheduleJob(cancellationToken);
}
protected virtual async Task ScheduleJob(CancellationToken cancellationToken)
{
var next = _expression.GetNextOccurrence(DateTimeOffset.Now, _timeZoneInfo);
if (next.HasValue)
{
var delay = next.Value - DateTimeOffset.Now;
if (delay.TotalMilliseconds <= 0) // prevent non-positive values from being passed into Timer
{
await ScheduleJob(cancellationToken);
}
_timer = new System.Timers.Timer(delay.TotalMilliseconds);
_timer.Elapsed += async (sender, args) =>
{
_timer.Dispose(); // reset and dispose timer
_timer = null;
if (!cancellationToken.IsCancellationRequested)
{
await DoWork(cancellationToken);
}
if (!cancellationToken.IsCancellationRequested)
{
await ScheduleJob(cancellationToken); // reschedule next
}
};
_timer.Start();
}
await Task.CompletedTask;
}
public virtual async Task DoWork(CancellationToken cancellationToken)
{
await Task.Delay(5000, cancellationToken); // do the work
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Stop();
await Task.CompletedTask;
}
public virtual void Dispose()
{
_timer?.Dispose();
}
}