Let's say I have an application and it has 10000k monthly users and I need to clean session data from database every 2 days, should I use the built-in background service in .net core or is it better and more performant to use hangfire? what is the best way to do this?
I made it as BackgroundService like this
public class SessionCleanupService : BackgroundService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public SessionCleanupService(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Wait until the next 15 day
var now = DateTime.Now;
var nextDay = now.AddDays(15).Date;
var delay = nextDay - now;
await Task.Delay(delay, stoppingToken);
// Delete expired data
using (var scope = _serviceScopeFactory.CreateScope())
{
var _context = scope.ServiceProvider.GetRequiredService<VincheckDbContext>();
var expiredData = await _context.Sessions
.Where(x => EF.Functions.DateDiffDay(x.UpdatedDate, now) > 2)
.ToListAsync();
_context.Sessions.RemoveRange(expiredData);
await _context.SaveChangesAsync();
}
}
}
}
If you need a simple and lightweight solution, you can use the built-in background service in .NET Core. This will allow you to run a task periodically without having to install any additional packages or dependencies.
If you need more advanced scheduling and control over the background tasks, then Hangfire is worth considering. Hangfire offers features such as delayed jobs, recurring jobs, and automatic retries. It also provides a dashboard for monitoring and managing your background jobs. However, using a third-party library may add complexity and additional dependencies to your application.
Do you really need all that additional functionality that Hangfire provides? Your scenario sounds simple enough to stuck the out of the box solution perhaps?
The main issue in your implementation I see is you are pulling a lot of data into memory just to delete, when you do a ToListAsync() it will evaluate the query and bring that into memory.
You can instead just do the delete of the query without evaluating the result
var expiredData = context.Sessions.Where(x => x.UpdatedDate < DateTime.UtcNow.AddDays(-2));
context.Sessions.RemoveRange(expiredData);
await context.SaveChangesAsync();