HostingEnvironment.QueueBackgroundWorkItem是否真的延迟了回收?

oav*_*ham 3 c# asp.net iis recycle

我已经阅读了该文档,该文档显示正在执行以下操作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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我已经运行check()(在IIS 7上),过了一段时间,我才通过IIS管理器强制进行了回收。

最后,我检查了debug.txt文件,它只包含一行:“即将回收...”。

因此,我猜想已发出CancellationToken信号,但是AppDomain Shutdown并没有真正延迟(因为第二次打印从未发生)。

看来这很奇怪,尤其是考虑到我读过的几篇文章说回收将被延迟30秒。

我想念什么吗?

Ste*_*ary 6

您正在使用async void,这就是让您感到困惑。正如我在有关异步最佳实践的MSDN文章中所描述的那样,您应该避免使用异步void。

更改async void为async Task,您可能会看到它正常工作。

更多信息:检测async void方法的完成并非易事,因此您发布的代码QueueBackgroundWorkItem实际上几乎立即(在第一个完成await)完成。关闭ASP.NET时,它将设置取消令牌(将第一行同步写入文件),然后等待所有排队的工作。由于工作已经完成,因此它立即关闭了应用程序域,放弃了该方法的其余部分。

如果您使用一种async Task方法,那么QueueBackgroundWorkItem在任务完成之前,代码将是不完整的。