首页 > 解决方案 > 如何在 C# ASP.NET 中等待异步

问题描述

我有以下问题:我需要执行一个处理 HTTP 请求后延迟的函数。用户可以分配某个任务,45 分钟后我必须检查任务是否完成。如果没有,我必须为其他人重新打开任务。

我尝试了以下代码:

[HttpPost]
[ActionName("addJob")]
public string AddJob([FromBody] Task task)
{
   // Add task ...

   RemoveTaskAfterTime(task);

   return "Job has been added";
}

private async Task RemoveTaskAfterTime(Task task)
{
   System.Diagnostics.Debug.WriteLine("started to wait");
   await Task.Delay(5000);
   System.Diagnostics.Debug.WriteLine("remove task");
}

出于某种原因,“开始等待”被调用,但“删除任务”没有。它适用于 Thread.sleep,但在这种情况下,响应也需要 45 分钟,所以这不是解决方案。如果有人可以帮助我,那就太棒了!先感谢您

标签: c#asp.nethttpasync-await

解决方案


您的问题是范围之一。

您可能没有考虑过这一点,但AddJob它是在类上定义的实例方法。IIS 通过实例化一个对象并调用该方法来处理 HTTP 请求。Task 运行的子线程在实例被释放时被杀死,因为后台线程在其所有者的所有前台线程都被终止时被杀死。这就是你的任务开始但没有结束的原因。

如果您希望任务在处理请求的对象中存活,那么您可以使任务及其生命周期管理静态。当然,这不适合接受任何数量的潜在并发请求的服务器,因此静态任务必须是您将任务对象放入其中的任务的集合。我们刚刚介绍了并发问题,因此您将需要一个线程安全队列

一旦你开始做这种事情,你就要对对象的生命周期负责,因为在你将它从集合中删除之前,它不会被垃圾回收。

您需要一个后台进程来定期检查每个对象的排队时间,并且当它们达到所需的年龄时,该进程应该将它们出列并在它们达到所需的年龄时执行任何应该发生的事情。这意味着您需要记录每个任务的时间。您将每个任务出列,检查它是否成熟,然后处理它或重新排队。

坦率地说,我不会使用 Task 对象,我会创建一个具有用于管理细节的属性和实现行为的方法的类。这是 Memento 和 Command 设计模式的组合。

正如在强大解决方案中的另一个答案中提到的,您的任务将在服务器重新启动后继续存在。您可以使用 Memento/Command 和持久消息队列代替内存队列来实现此目的。在 Windows 上,MSMQ 是免费提供的。这种方式的一个优点是 MSMQ 接管了队列管理中线程安全的责任。

要使用外部消息队列,您需要了解(反)序列化。另一个答案使用数据库服务器而不是消息队列来持久化序列化消息,这确实有效,但不能很好地扩展。专门构建的消息队列依赖于一系列无法​​在通用数据库引擎中做出的假设,这使它们能够更稳健地处理计划外中断并处理更高级别的并发(或对给定级别的服务器施加更少的压力)流量)。


推荐阅读