前段时间,我在“System.Timers”的帮助下创建了自己创建的调度程序。我将向您展示这段代码:
public class Scheduler
{
private const int MSecond = 1000;
private readonly int _seconds = MSecond * 10;
private Timer _aTimer;
public void Start()
{
Console.WriteLine("Sending is started ...");
_aTimer = new Timer();
_aTimer.Interval = _seconds;
_aTimer.Elapsed += OnTimedEvent;
_aTimer.AutoReset = true;
_aTimer.Enabled = true;
}
public bool IsWorking()
{
return _aTimer != null;
}
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
await JustDoIt();
}
private async Task JustDoIt()
{
_aTimer.Stop();
// big and difficult work
await Task.Delay(1000 * 12);
Console.WriteLine("Done !!");
_aTimer.Start();
}
public void Stop()
{
_aTimer.Stop();
_aTimer = null;
}
}
所以,为了确保我在开始新的工作之前完成了一项工作,我只是在开始工作后直接取消我的计时器。然后,当工作完成后,我打开计时器。当多个并行作业试图访问资源或一起写入数据库时,这有助于我避免错误。而我的业务规则直接告诉我:工作是一个接一个,而不是一起。
一切都很好,但我决定重写 Scoped Hosted Background 服务。这是微软文档。我会告诉你结果:
IScopedProcessingService
internal interface IScopedProcessingService
{
Task DoWork(CancellationToken stoppingToken);
}
ConsumeScopedServiceHostedService
public class ConsumeScopedServiceHostedService : BackgroundService
{
private readonly ILogger<ConsumeScopedServiceHostedService> _logger;
public ConsumeScopedServiceHostedService(IServiceProvider services,
ILogger<ConsumeScopedServiceHostedService> logger)
{
Services = services;
_logger = logger;
}
public IServiceProvider Services { get; }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
_logger.LogInformation("Consume Scoped Service Hosted Service is working.");
while (!stoppingToken.IsCancellationRequested) {
using (var scope = Services.CreateScope()) {
IServiceProvider serviceProvider = scope.ServiceProvider;
var service = serviceProvider.GetRequiredService<IScopedProcessingService>();
await service.DoWork(stoppingToken);
}
//Add a delay between executions.
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service is stopping.");
await Task.CompletedTask;
}
}
和ScopedProcessingService
internal class ScopedProcessingService : IScopedProcessingService
{
// here is injections and constructor
public async Task DoWork(CancellationToken stoppingToken)
{
// a job with no fixed time. Sometimes it's minute, sometimes it's more, sometimes it's less
await Task.Delay(TimeSpan.FromSeconds(40));
}
}
而在Startup.cs
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedProcessingService, ScopedProcessingService>();
那么如何保护我的应用程序免受并行作业的影响?我需要一个一个。在上面的示例中,下一个任务将在 10 秒后开始。但是,如果我猜对了,之前的任务会在这个时候继续进行!这意味着我的数据库可能因此而混乱。