Web Api - 火与忘记

D. *_*es 26 c# rest task-parallel-library asp.net-web-api

我有一个Web API的操作,我需要运行一些任务而忘记这个任务.这就是我的方法现在的组织方式:

public async Task<SomeType> DoSth()
{
    await Task.Run(...);
    .....
    //Do some other work
}
Run Code Online (Sandbox Code Playgroud)

事情是,显然它停在等待线等待它完成后才继续工作.我需要"解雇并忘记"我是否应该在没有任何异步等待的情况下调用Task.Run()?

Ste*_*ary 26

我需要"开除并忘记"

我有一篇博文,详细介绍了几种不同的ASP.NET方法.

总结:首先,尽量不要忘掉.这几乎总是一个坏主意.你真的想"忘记"吗?如在,不关心它是否成功完成?忽略任何错误?在没有任何日志通知的情况下接受偶尔"丢失工作"?几乎总是,答案是否定的,"即发即忘"不是合适的方法.

可靠的解决方案是构建适当的分布式架构.也就是说,构造一个表示要完成的工作的消息,并将该消息排队到可靠的队列(例如,Azure队列,MSMQ等).然后有一个独立的后端处理该队列(例如,Azure WebJob,Win32服务等).

我应该在没有任何async-await的情况下调用Task.Run()吗?

不,这是最糟糕的解决方案.如果你必须做好点火,并且你不愿意构建分布式架构,那么考虑一下Hangfire.如果不适合你的工作,那么至少要注册通过ASP.NET运行时的牛仔背景的工作HostingEnvironment.QueueBackgroundWorkItem或我的ASP.NET后台任务库.请注意,QBWI和AspNetBackgroundTasks都是不可靠的解决方案; 他们只是你失去工作的机会降到最低,而不是阻止它.

  • 我不喜欢人们说一劳永逸几乎总是一个坏主意的情绪,但我同意警告。就我而言,我会*预先* 进行请求和日志记录,如果任务成功,用户会收到通知,或者如果任务失败,则作业会让他们知道。他们还可以检查状态,如果没有成功就被禁止继续,他们必须重试。为什么这是个坏主意?只需设计到位以解决故障,以便解决它们。 (2认同)

Fer*_*min 9

在asp.net中,真正的火灾和遗忘任务可能很困难,因为它们通常会随着它们作为其一部分创建的请求而死亡.

如果您使用的是4.5.2+,则可以使用QueueBackgroundWorkItem来运行任务.通过这种方法注册任务,AppDomain将尝试延迟关闭,直到它们全部完成,但仍然有可能在它们完成之前被杀死的实例.这可能是最简单的事情,但值得一读,以确切了解哪些实例可以导致取消作业.

HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken =>
{
  await Task.Run(...);
});
Run Code Online (Sandbox Code Playgroud)

有一个名为hangfire的工具,它使用持久存储来确保任务已完成并具有内置的重试和错误记录功能.这更适用于"后台任务",但确实适合火灾和遗忘.这是相对容易设置,并提供各种支持商店,我不记得确切的细节,但有些需要许可证,有些则不需要(如MSSQL).


Cat*_*lin 8

为了避免火灾,请使用此

Task.Factory.StartNew(async () =>
{
    using (HttpClient client = new HttpClient())
    {
        await client.PostAsync("http://localhost/api/action", new StringContent(""));
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,至少是一个明确的答案,所有其他尖叫“不要这样做”的人似乎都没有看到好处 (3认同)
  • 好的,以它为例,但是请不要每次都像这样创建一个新的 HttpClient 实例。请记住,HttpClient 旨在作为单例重新使用,否则您可能会面临套接字耗尽。有关更多信息,请查看这两篇博客文章: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ https://www.nimaara.com/beware-of-the-net-httpclient/ (3认同)

小智 5

我使用HangFire

这对我来说是最好的。

在 .NET 和 .NET Core 应用程序中执行后台处理的一种简单方法。无需 Windows 服务或单独的进程。

由持久存储支持。开放并免费用于商业用途。


Jer*_*ert 1

永远不要一劳永逸,因为这样你就不会看到任何错误,如果出现问题,这会导致一些非常尴尬的故障排除(让任务方法执行自己的异常处理并不能保证工作,因为任务可能不会首先成功启动)。除非您真的不介意该任务是否执行任何操作,但这很不寻常(因为,如果您真的不关心,为什么首先要运行该任务)?至少,创建带有延续的任务:

Task.Run(...)
  .ContinueWith(t => 
    logException(t.Exception.GetBaseException()),
    TaskContinuationOptions.OnlyOnFaulted
  )
;
Run Code Online (Sandbox Code Playgroud)

您可以根据需要使其变得更加复杂。

在 Web API 的特定情况下,您实际上可能希望等待后台任务完成后再完成请求。如果你不这样做,你就会让一些东西在后台运行,这些东西可能会歪曲你的服务真正可以承受的负载量,或者如果客户端发出太多请求而你没有采取任何措施来限制它们,甚至会完全停止工作。您可以收集任务并await Task.WhenAll(...)在最后发出一个任务来实现这一目标;这样,当后台任务缓慢进行时,您可以继续做有用的工作,但在一切完成之前您不会返回。

  • 我想解雇并忘记,因为我有可以获取流程状态的操作。这对我来说并不重要,因为首先完成基本的数据库更新,然后运行任务。如果任务失败,用户将无法继续,因为数据库未更新,并且将要求他们重试。 (2认同)