我要求后台服务应该在Process
每天早上 0:00 运行方法
因此,我的一位团队成员编写了以下代码:
public class MyBackgroundService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private Timer _timer;
public MyBackgroundService(ILogger<MyBackgroundService> logger)
{
_logger = logger;
}
public void Dispose()
{
_timer?.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
TimeSpan interval = TimeSpan.FromHours(24);
TimeSpan firstCall = DateTime.Today.AddDays(1).AddTicks(-1).Subtract(DateTime.Now);
Action action = () =>
{
Task.Delay(firstCall).Wait();
Process();
_timer = new Timer(
ob => Process(),
null,
TimeSpan.Zero,
interval
);
};
Task.Run(action);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
private Task Process()
{
try
{
// perform some database operations
}
catch (Exception e)
{
_logger.LogError(e, e.Message);
}
return Task.CompletedTask;
}
}
此代码按预期工作。但我不喜欢它同步等待直到Process
第一次调用,所以线程被阻塞并且没有执行任何有用的工作(如果我错了,请纠正我)。
我可以像这样进行异步操作并在其中等待:
public Task StartAsync(CancellationToken cancellationToken)
{
// code omitted for brevity
Action action = async () =>
{
await Task.Delay(firstCall);
await Process();
// code omitted for brevity
}
但是我不确定Task.Run
在这里使用是一件好事,因为Process
方法应该执行一些 I/O 操作(查询数据库并插入一些数据),并且不建议Task.Run
在 ASP.NET 环境中使用。
我重构StartAsync
如下:
public async Task StartAsync(CancellationToken cancellationToken)
{
TimeSpan interval = TimeSpan.FromHours(24);
TimeSpan firstDelay = DateTime.Today.AddDays(1).AddTicks(-1).Subtract(DateTime.Now);
await Task.Delay(firstDelay);
while (!cancellationToken.IsCancellationRequested)
{
await Process();
await Task.Delay(interval, cancellationToken);
}
}
这让我根本不用定时器MyBackgroundService
。
我应该使用“timer + Task.Run”的第一种方法还是使用“while loop + Task.Delay”的第二种方法?