WebAPI 中长时间运行的任务

Posted

技术标签:

【中文标题】WebAPI 中长时间运行的任务【英文标题】:Long running task in WebAPI 【发布时间】:2013-07-08 18:13:09 【问题描述】:

这是我的问题:我需要在 ApiController 中调用多个第 3 方方法。这些方法的签名是Task DoSomethingAsync(SomeClass someData, SomeOtherClass moreData)。在 ApiController 将数据发送回客户端后,我希望这些调用继续在后台运行。当DoSomethingAsync 完成时,我想做一些日志记录,并可能将一些数据保存到文件系统中。我怎样才能做到这一点?我更喜欢使用 asyny/await 语法。

【问题讨论】:

你的任务类似于.ContinueWith。这是您可以进行日志记录的地方。 当您说“ApiController 将数据发送回客户端后”时,您的意思是连接也关闭了吗?客户端可以在保持连接打开的同时从服务器接收数据吗? 是的,连接已关闭。 签出hangfire.io 对于 .Net Core 2.x,请查看 IHostedService。此博客中的一个很好的例子:stevejgordon.co.uk/asp-net-core-2-ihostedservice。类似于hangfire的概念。 【参考方案1】:

好消息,.NET 4.5.2 中有一个名为 QueueBackgroundWorkItem API 的新解决方案。使用起来真的很简单:

HostingEnvironment.QueueBackgroundWorkItem(ct => DoSomething(a, b, c));

这是一篇详细描述它的文章。

https://blogs.msdn.microsoft.com/webdev/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-background-processes-in-asp-net/

这里还有一篇文章提到了这个线程中没有提到的其他一些方法。 http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx

【讨论】:

QueueBackgroundWorkItem 如果长时间运行的任务不是真的那么长时间运行,即如果它可以在不到 90 秒内完成,则可能是一个解决方案。如果它确实需要长时间运行,则需要另一个解决方案(例如将其交给 Windows 服务) 我无法让它在 Windows 服务(后端数据层)内的自托管 WebAPI 中工作。【参考方案2】:

你几乎不想这样做。这几乎总是一个大错误。

ASP.NET(和大多数其他服务器)的工作假设是,一旦所有请求完成,就可以安全地关闭您的服务。因此,您无法保证您的日志记录会完成,或者您的数据将被写入磁盘。尤其是磁盘写入,您的写入完全有可能被破坏。

也就是说,如果您绝对确定要实施这种极其危险的设计,则可以使用BackgroundTaskManager from my blog。

更新:我写了一个博客系列,详细介绍了 proper solution for request-extrinsic code。总之,您真正想做的是将请求外部代码移出 ASP.NET。引入持久队列和独立处理器; ASP.NET 控制器操作会将请求放入队列,独立处理器将读取请求并执行它们。这个“处理器”可以是 Azure Function/WebJob、Win32 Service 等。

【讨论】:

在 Azure-WebJobs 之前更正。现在,您可以使用 Azure-WebJobs 执行此操作。工人角色是最可靠的方法。 我发现这是一个可接受的折衷方案,例如:调试日志记录、性能记录、事件跟踪(使用外部服务)。在所有这些情况下,“即发即弃”语义是可以接受的,我们并不真正关心个别事件是否会在服务中断的情况下丢失。还是我缺少什么? @JohannesRudolph:我想说主要用例是缓存更新。如果您接受您的日志可能没有所有数据,那么这是一种可接受的日志记录方式。我会将“事件跟踪”解释为业务需求,因此不是一个好的用例。如果“事件跟踪”不重要,那么“调试日志记录”、“性能记录”和“事件跟踪”只是三种不同的日志记录。请注意,ASP.NET 4.5.2 现在内置了类似的东西。【参考方案3】:

Stephen 描述了为什么在 ApiController 中启动基本上长时间运行的即发即弃任务是一个坏主意。

也许您应该创建一个单独的服务来执行那些即发即弃的任务。该服务可以是不同的 ApiController、队列后面的工作人员、任何可以独立托管并具有独立生命周期的东西。

这将使不同任务生命周期的管理变得更加容易,并将长期运行任务的关注点与 ApiController 的核心职责分开。

【讨论】:

最好有一个单独的服务的另一个原因是更容易横向扩展。例如,也许您发现需要更多服务器来运行长时间运行的任务,但不需要更多服务器来运行您的网站。通过在开始时将它们拆分,您可以更好地自定义横向扩展解决方案。 如何实现? @KiranAhir 在文档中进行了解释:Background tasks with hosted services in ASP.NET Core。在 Web 应用程序中,您可以创建一个 BackgroundService 来处理长任务。您还可以使用后台服务创建一个单独的 Web API 项目,以接收来自前端 Web 应用程序的请求。甚至还有一个创建独立后台服务的 Worker Service 模板【参考方案4】:

正如其他人指出的那样,不建议这样做。不过,有需要就有办法,快来看看IRegisteredObject

另见

http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx/

【讨论】:

【参考方案5】:

虽然这个问题已经存在好几年了,但现在最好的解决方案是在这种情况下使用 Singal R。

https://github.com/Myrmex/signalr-notify-progress

【讨论】:

以上是关于WebAPI 中长时间运行的任务的主要内容,如果未能解决你的问题,请参考以下文章

如何验证对 Piranha.WebApi 的调用?

通过HTTP请求WEBAPI的方式

webapi + windows计划 + mshta 实现定时执行任务

调试异步 ASP.NET WebAPI 控制器在“任务”窗口中显示“没有要显示的任务”

WebApi-控制器路由

尝试运行 WebAPI 时,Visual Studio 显示“选择智能卡设备”窗口