【发布时间】:2022-11-06 03:23:21
【问题描述】:
用于后台服务的 ASP.NET Core docs 显示了许多实现示例。
有一个在timer 上启动服务的示例,尽管它是同步的。还有另一个异步示例,用于使用scoped dependency 启动服务。
我需要两者都做:每 5 分钟启动一次服务,并且它具有范围依赖性。没有例子。
我结合了这两个示例,但我不确定将Timer 与异步TimerCallback 一起使用的安全方法。
例如
public class MyScheduler : IHostedService
{
private Timer? _timer;
private readonly IServiceScopeFactory _serviceScopeFactory;
public MyScheduler(IServiceScopeFactory serviceScopeFactory) => _serviceScopeFactory = serviceScopeFactory;
public void Dispose() => _timer?.Dispose();
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer((object? state) => {
using var scope = _serviceScopeFactory.CreateScope();
var myService = scope.ServiceProvider.GetRequiredService<IMyService>();
await myService.Execute(cancellationToken); // <------ problem
}), null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) {
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
}
计时器接受同步回调,所以问题出在await。调用异步服务的安全方法是什么?
【问题讨论】:
-
myService.Execute是否有可能需要 5 分钟以上才能完成?在这种情况下,你希望发生什么?您对方法的重叠执行感到满意吗? -
您可能会发现这很有用:Run async method regularly with specified interval。从长远来看,在事件处理程序中添加临界区可能会导致
ThreadPool饱和,因为在计时器计时时可能会阻塞越来越多的线程。 -
@lonix 是的,Artur 的answer 防止重叠,因为它不涉及基于事件的
Timer,它调用ThreadPool上的事件处理程序。 -
@lonix“选项2”也可以防止重叠。
PeriodicTimer是 awaitable timer,而不是基于事件的计时器。 -
@TheodorZoulias 您的 cmets 与下面的答案一样有帮助,谢谢!
标签: c# asp.net-core async-await asp.net-core-5.0 asp.net-core-hosted-services