问题
I am creating a worker service which will be run as a windows service. I have a requirement where I would like to invoke two tasks which may have different timers.
Say DoWork
should be called every 5 minutes and DoAnotherWork
should be called every 10 minutes or so. These two tasks can run in parallel and are not dependant on each other.
I was able to create task DoWork
which can run after every 5 minutes. I am a bit confused about how to implement another task that will have different timer duration?
public class Worker : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private IDataLoaderService _dataLoaderService;
public override Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
_dataLoaderService = scope.ServiceProvider.GetRequiredService<IDataLoaderService>();
return base.StartAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await DoWork(stoppingToken, _dataLoaderService);
await Task.Delay(300000, stoppingToken); //Run every 5 minutes
await DoAnotherWork(stoppingToken, _dataLoaderService);
await Task.Delay(600000, stoppingToken); //Run every 10 minutes
}
}
private async Task DoWork(CancellationToken stoppingToken, IDataLoaderService loaderService)
{
await loaderService.Process();
}
private async Task DoAnotherWork(CancellationToken stoppingToken, IDataLoaderService loaderService)
{
await loaderService.Validate();
}
}
回答1:
These two tasks can run in parallel and are not dependant on each other.
Sounds to me like you have two services:
public class ProcessDataLoaderWorker : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var scope = _scopeFactory.CreateScope();
var dataLoaderService = scope.ServiceProvider.GetRequiredService<IDataLoaderService>();
while (true)
{
await dataLoaderService.Process();
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); //Run every 5 minutes
}
}
}
public class ValidateDataLoaderWorker : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var scope = _scopeFactory.CreateScope();
var dataLoaderService = scope.ServiceProvider.GetRequiredService<IDataLoaderService>();
while (true)
{
await dataLoaderService.Validate();
await Task.Delay(TimeSpan.FromMinutes(10), stoppingToken); //Run every 10 minutes
}
}
}
I also modified the way the IDataLoaderService
was used so that it is not used outside its scope, and changed the Task.Delay
arguments to be more self-explanatory.
回答2:
If you don't want to use existing scheduling libraries in your case you can go with having two timers, like in this docs, where System.Threading.Timer
is utilized. Something like that:
public class Worker : IHostedService, IDisposable
{
private readonly IServiceScopeFactory _scopeFactory;
private IDataLoaderService _dataLoaderService;
private Timer _timer1;
private Timer _timer2;
public Task StartAsync(CancellationToken cancellationToken)
{
_dataLoaderService = scope.ServiceProvider.GetRequiredService<IDataLoaderService>();
_timer1 = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(300));
_timer2 = new Timer(DoAnotherWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(600));
return Task.CompletedTask;
}
private async void DoWork(object _)
{
// or create scope and resolve here
await _loaderService.Process();
}
private async void DoAnotherWork(object _)
{
// or create scope and resolve here
await _loaderService.Validate();
}
public Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Timed Hosted Service is stopping.");
_timer1?.Change(Timeout.Infinite, 0);
_timer2?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer1?.Dispose();
_timer2?.Dispose();
}
}
来源:https://stackoverflow.com/questions/63004613/how-to-run-multiple-task-in-background-service-in-net-core-with-different-timer