I'm using the BackgroundService - is it possible to have multiple task in one background service project in .NET Core with different timer duration:
FirstLoop - execute every second
SecondLoop - execute every minute
ThirdLoop - execute every hour
ForthLoop - execute every day
I read the question which is related to the topic but it seems from 3 years ago and I'm wondering if there is a new approach to achieve this
How to run multiple task in background service in .net core with different timer duration
For some reason only the FirstLoop is been executed and every loop after it is not been executed. What are my options to make this work?
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
if (double.TryParse(_configuration["FirstLoop"], out double firstLoopExecution))
{
using PeriodicTimer timer = new PeriodicTimer(TimeSpan.FromSeconds(firstLoopExecution));
while (!stoppingToken.IsCancellationRequested &&
await timer.WaitForNextTickAsync(stoppingToken))
{
//Wrap any invocations inside this while loop into a try catch so that when one run of the while loop fails, it doesn’t break the entire method meaning the periodic loop continues
try
{
await DoFirstWorkAsync();
}
catch (Exception ex)
{
_logger.LogError("Error in first loop , " + ex.Message + ", InnerException ex:" + ex.GetOriginalException()?.Message + ", stackTrace:" + ex.StackTrace);
}
}
}
else
{
_logger.LogError("Missing FirstLoop configuration");
}
if (double.TryParse(_configuration["SecondLoop"], out double secondLoopExecution))
{
using PeriodicTimer timer = new PeriodicTimer(TimeSpan.FromSeconds(secondLoopExecution));
while (!stoppingToken.IsCancellationRequested &&
await timer.WaitForNextTickAsync(stoppingToken))
{
//Wrap any invocations inside this while loop into a try catch so that when one run of the while loop fails, it doesn’t break the entire method meaning the periodic loop continues
try
{
await DoSecondWorkAsync();
}
catch (Exception ex)
{
_logger.LogError("Error in second loop , " + ex.Message + ", InnerException ex:" + ex.GetOriginalException()?.Message + ", stackTrace:" + ex.StackTrace);
}
}
}
else
{
_logger.LogError("Missing SecondtLoop configuration");
}
if (double.TryParse(_configuration["ThirdLoop"], out double thirdLoopExecution))
{
using PeriodicTimer timer = new PeriodicTimer(TimeSpan.FromSeconds(thirdLoopExecution));
while (!stoppingToken.IsCancellationRequested &&
await timer.WaitForNextTickAsync(stoppingToken))
{
//Wrap any invocations inside this while loop into a try catch so that when one run of the while loop fails, it doesn’t break the entire method meaning the periodic loop continues
try
{
await DoThirdWorkAsync();
}
catch (Exception ex)
{
_logger.LogError("Error in first loop , " + ex.Message + ", InnerException ex:" + ex.GetOriginalException()?.Message + ", stackTrace:" + ex.StackTrace);
}
}
}
else
{
_logger.LogError("Missing ThirdLoop configuration");
}
if (double.TryParse(_configuration["ForthLoop"], out double forthLoopExecution))
{
using PeriodicTimer timer = new PeriodicTimer(TimeSpan.FromSeconds(forthLoopExecution));
while (!stoppingToken.IsCancellationRequested &&
await timer.WaitForNextTickAsync(stoppingToken))
{
//Wrap any invocations inside this while loop into a try catch so that when one run of the while loop fails, it doesn’t break the entire method meaning the periodic loop continues
try
{
await DoForthWorkAsync();
}
catch (Exception ex)
{
_logger.LogError("Error in first loop , " + ex.Message + ", InnerException ex:" + ex.GetOriginalException()?.Message + ", stackTrace:" + ex.StackTrace);
}
}
}
else
{
_logger.LogError("Missing ForthLoop configuration");
}
}
If you look at the first part of your ExecuteAsync
method, the code does not exit the while (!stoppingToken.IsCancellationRequested && await timer.WaitForNextTickAsync(stoppingToken))
block because the conditions are not changing under normal running which is why your other timers are never started.
The simplest change is to refactor the ExecuteAsync
method into 4 different methods and then call them all in parallel
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var tasks = new List<Task>() {
ExecuteFirstAsync(stoppingToken),
ExecuteSecondAsync(stoppingToken),
ExecuteThirdAsync(stoppingToken),
ExecuteFourthAsync(stoppingToken)
};
await Task.WhenAll(tasks);
}
but a better solution might be to break them up into multiple classes and register them independently
services.AddHostedService<FirstService>();
services.AddHostedService<SecondService>();
services.AddHostedService<ThirdService>();
services.AddHostedService<FourthService>();