Web Api – 火与忘记

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

public async Task DoSth() { await Task.Run(...); ..... //Do some other work } 

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

我需要“开除并忘记”

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

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

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

我应该在没有任何异步等待的情况下调用Task.Run()吗?

不,这是最糟糕的解决方案。 如果你必须做好事,而且你不愿意建立分布式架构,那么考虑一下Hangfire。 如果这对您不起作用,那么至少应该通过HostingEnvironment.QueueBackgroundWorkItem或我的ASP.NET后台任务库向ASP.NET运行时注册您的牛仔背景工作。 请注意,QBWI和AspNetBackgroundTasks都是不可靠的解决方案; 他们只是尽量减少你失去工作的机会,而不是阻止它。

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

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

 HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => { await Task.Run(...); }); 

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

永远不要忘记,因为那样你就不会看到任何错误,这会导致一些非常尴尬的故障排除,如果出现问题(让任务方法做自己的exception处理不能保证工作,因为任务可能不会首先成功开始)。 除非你真的不介意任务是否做了什么,但这是非常不寻常的(因为,如果你真的不在乎,为什么要首先执行任务)? 至少,使用延续创建您的任务:

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

根据您的需求,您可以使其更加复杂。

在Web API的特定情况下,您可能实际上希望在完成请求之前等待后台任务完成。 如果你不这样做,你就会留下在后台运行的东西,这些东西可能会歪曲你的服务真正需要多少负载,或者如果客户端发出太多请求并且你没有采取任何措施来阻止它们,那么甚至会完全停止工作。 您可以收集任务并在最后发出await Task.WhenAll(...)以实现该目的; 通过这种方式,您可以在后台任务逐渐消失的情况下继续执行有用的工作,但在完成所有操作之前,您不会返回。

对于火灾和遗忘,请使用此function

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

我使用HangFire 。

这对我来说是最好的。

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

以持久存储为后盾。 开放和免费用于商业用途。

我同意其他人的意见,你不应该忘记你的电话。 但是,要回答您的问题,如果从Task.Run()行中删除等待,则调用将不会阻塞,如此处所示

 public async Task DoSth() { Task.Run(...); ..... //Do some other work while Task.Run() continues in parallel. } 

这里有一些post推动“永不发火,忘记”,错误等。

事实是,从某些观点来看,这并没有错。 在某些方面错误地描述了。

真正应该说的是“用户应该能够解雇并忘记,但它仍然应该告诉开发人员/所有者。”

一个很好的例子是在网站上联系我们表格。 客户填写表格并在幕后通过电子邮件向网站所有者发送电子邮件。 有些电子邮件服务器需要很长时间来处理发送,因此像Hangfire这样的软件包(我会使用它)会将其发送到网络服务器“线程”之外的另一个进程。

是的,如果发生错误,这应该以某种方式告知开发人员/所有者(并保留联系人详细信息)。 但这绝不应该告诉潜在的联系人。 (除非你想失去潜在客户)

为了调用fire并忘记WebApi方法,我使用以下代码来确保它返回OK响应 。 我的情况是,登录时创建的不记名授权令牌存储在cookie中:

 ... FireAndForget().Wait(); ... private async Task FireAndForget() { using (var httpClient = new HttpClient()) { HttpCookie cookie = this.Request.Cookies["AuthCookieName"]; var authToken = cookie["AuthTokenPropertyName"] as string; httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken); using (var response = await httpClient.GetAsync("http://localhost/api/FireAndForgetApiMethodName")) { //will throw an exception if not successful response.EnsureSuccessStatusCode(); } } }