.NET Core IHostedService 立即抛出"A task was canceled"



我正在尝试在我的.NET Core 3.1应用程序中构建一个每小时运行的服务。我的服务每小时运行一次(即在StartAsync()中遇到断点),但实现立即抛出以下错误:

任务已取消

我已经搜索了很多,但是我很难找到有用的回复; 似乎这些在使用HttpClient时最常抛出,这与我的情况无关。

也就是说,我有一种预感,我应该等待一些东西,但我尝试添加await导致应用程序在启动时挂起(我想我无意中等待了整小时的迭代......?我一直在关注的教程在任何地方都没有使用await;除非有疏忽(很有可能),否则我的代码似乎与所示示例相同。

我已经拿出ExecuteAll()的胆量来确认作品中的代码。

谢谢。

public Task StartAsync(CancellationToken cancellationToken)
{
TimeSpan interval = TimeSpan.FromHours(1);
var nextRunTime = DateTime.Today.AddHours(DateTime.UtcNow.Hour + 1);
var curTime = DateTime.UtcNow;
var firstInterval = nextRunTime.Subtract(curTime);
//Run once on startup
TriggerHourlyService(null);
void action()
{
//Schedule the first iteration
var t1 = Task.Delay(firstInterval);
t1.Wait();
TriggerHourlyService(null);
//Schedule hourly
_timer = new Timer(
TriggerHourlyService,
null,
TimeSpan.Zero,
interval
);
}
Task.Run(action);
return Task.CompletedTask;
}
private void TriggerHourlyService(object state)
{
using var scope = _serviceScopeFactory.CreateScope();
IHourlyService hourlyService = scope.ServiceProvider.GetRequiredService<IHourlyService>();
//ASYNC METHOD
hourlyService.ExecuteAll();
}

更新

在评论中的一些注释之后,我稍微重写了代码以远离教程(似乎它正在推广一些危险的做法)。但是,通过此重写,我的应用程序在启动时挂起。我相信这是导致问题await Task.Delay(...),但我的印象是这是非阻塞的。

public async Task StartAsync(CancellationToken cancellationToken)
{
TimeSpan interval = TimeSpan.FromHours(1);
var nextRunTime = DateTime.UtcNow.Date.AddHours(DateTime.UtcNow.Hour + 1);
var curTime = DateTime.UtcNow;
var firstInterval = nextRunTime.Subtract(curTime);
//Run once on startup
await TriggerHourlyService(null);
//First run on next hour
await Task.Delay(firstInterval);
await TriggerHourlyService(null);
//Schedule hourly
_timer = new Timer(
async (state) => await TriggerHourlyService(state),
null,
TimeSpan.Zero,
interval
);
}
private async Task TriggerHourlyService(object state)
{
using var scope = _serviceScopeFactory.CreateScope();
IHourlyService hourlyService = scope.ServiceProvider.GetRequiredService<IHourlyService>();
await hourlyService.ExecuteAll();
}

如果您想在主机程序启动和停止时运行代码,IHostedServce非常有用。您定义的每个服务都将按照您定义的顺序启动和停止。但是,如果启动方法从未完成,则主机应用程序将永远不会启动。

如果您想要的只是一个长时间的运行循环,BackgroundService会为您处理开始/停止生命周期。

public class MyService : BackgroundService{
protected override async Task ExecuteAsync(CancellationToken stoppingToken){
while(!stoppingToken.IsCancellationRequested){
await Task.Delay(...., stoppingToken);
//
}
}
}

请注意,如果您从未await未完成的任务,您的服务仍可以阻止主机的启动。

相关内容

最新更新