所以我遇到了一些让我感到不舒服的代码,但是我无法找到关于它是否真的有问题的明确答案。
我们有一个主要由消息总线使用的ASP.Net Web API。需要为多个帐户启动平衡过程。平衡服务方法是异步的并返回一个Task。代码的调用方式如下:
foreach (AccountingGroup accountingGroup in Groups)
{
ledgerService.CreateItemsAsync(accountingGroup.GLAccountingHeaderId);
}
return StatusCode(HttpStatusCode.NoContent);
这在很多层面上让我感到错误。我明白了。 "我们希望在所有这些群组上运行此方法,但我们不需要等待它们完成。
显然,取消令人不被使用。他们依赖AWS只是为了杀死整个过程,如果它持续很长时间,并且这不是我现在可以真正进入的重构。
我已经退出C#一年半了,异步代码已经用了2。5年了,感觉我在某个时候知道这个问题,但我再也找不到了。< / p>
处理此问题的正确方法是什么?这甚至是个问题吗?
答案 0 :(得分:3)
正确的方法是将API方法定义为异步,然后等待所有异步方法完成:
public Task<IHttpActionResult> DoStuff()
{
await Task.WhenAll(groups.Select(g =>
ledgerService.CreateItemsAsync(g.GLAccountingHeaderId));
return StatusCode(HttpStatusCode.NoContent);
}
帕特里克的答案解释了“为什么”。如果一个动作没有完成就假装给客户似乎是一个坏主意。
如果您想在后台运行这些内容,您可能会考虑使用像RabbitMq这样的消息队列,并开发一种确保完成这些任务的故障安全方法。事情失败时的反馈是好的。使用您当前的方法,您绝对无法确定此代码是否失败,这意味着如果它停止工作,您将无法实现,直到它影响其他内容。
答案 1 :(得分:3)
这甚至是个问题吗?
是的,不想等待它,实际上能够处理异常是有区别的。
例如,如果您的代码因任何原因失败,您现在返回HTTP 204,即成功状态。如果您要等待结果,但它失败了,您最有可能获得HTTP 500。
处理此问题的正确方法是什么?
您应该等待结果,例如汇总任务并在其上调用Task.WhenAll
,这样您就不必分别等待每一项任务。
答案 2 :(得分:3)
不,不行,服务器可能会在后台运行时关闭应用程序域。处理此问题的最佳方法是使用库来进行后台工作,例如https://www.hangfire.io/。
如果您认为工作将在下一分钟左右完成,您可以使用短期系统HostingEnvironment.QueueBackgroundWorkItem(Func<CancellationToken,Task>)
但是我不确定这是否适用于ASP.NET Core,它的设计是与以前版本的ASP.NET一起使用。
编辑:找到一个引用,QueueBackgroundWorkItem确实在ASP.NET Core中不起作用,但有a similar way to handle these situations there。
答案 3 :(得分:0)
您可以使用QueueBackgroundWorkItem
请查看Getting QueueBackgroundWorkItem to complete if the web page is closed