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 中长时间运行的任务的主要内容,如果未能解决你的问题,请参考以下文章
webapi + windows计划 + mshta 实现定时执行任务