我已阅读this documentation,其中表示正在使用HostingEnvironment.QueueBackgroundWorkItem
:
与普通的ThreadPool工作项不同,ASP.NET可以跟踪当前正在运行的通过此API注册的工作项数,并且ASP.NET运行时将尝试延迟AppDomain关闭,直到这些工作项完成执行。无法在ASP.NET管理的AppDomain之外调用此API。提交的CancellationToken将在应用程序关闭时发出信号。
所以我写了这个示例代码:
private void Check() {
HostingEnvironment.QueueBackgroundWorkItem(ct => CheckRecyclingBehaviour(ct));}
}
private async void CheckRecyclingBehaviour(CancellationToken ct) {
while (true) {
await Task.Delay(1000);
if (ct.IsCancellationRequested) {
AppendToFile("Recycling soon...");
await Task.Delay(1000);
AppendToFile("But we still have time to finish...");
break;
}
}
}
我已经运行check()
(在IIS 7上),过了一段时间我强制通过IIS管理器进行回收。
最后,我已经解决了debug.txt文件,它包含了一行:“很快回收......”。
所以我认为CancellationToken已发出信号,但AppDomain Shutdown并未真正延迟(因为第二次打印从未发生过)。
这看起来很奇怪,特别是考虑到我读过的几篇帖子都说recycling will be delayed by 30 seconds。
我错过了什么吗?
答案 0 :(得分:5)
您正在使用async void
,这就是让您烦恼的原因。正如我在my MSDN article on async best practices, you should avoid async void中描述的那样。
将async void
更改为正确的async Task
,您可能会看到它正常运行。
更多信息:检测async void
方法的完成情况非常重要,因此您发布到QueueBackgroundWorkItem
的代码几乎立即完成(在第一个await
})。当ASP.NET关闭时,它会设置取消令牌(同步将第一行写入文件),然后等待任何排队的工作。由于工作已经完成,它只是立即拆除app域,放弃了方法的其余部分。
如果您使用async Task
方法,则QueueBackgroundWorkItem
会在任务完成之前了解代码未完成。