【发布时间】:2015-02-12 04:25:20
【问题描述】:
我有多个异步方法,它们都会对其他服务器进行 httpclient 调用。我想在 webapi 调用结束时运行这些并立即返回。每个调用都需要记录它们所花费的时间,当全部完成时,我需要将这些时间记录到一个文件中。我花了一些时间修修补补,直到我让它发挥作用,但我不知道为什么它有效,而其他方式则无效。
您能帮我解释一下吗?
这是行不通的基本方法。也就是说,调用了,但 LogTimeTaken 没有(或至少没有写入日志文件)。
//inside webapi action
var tasks = new List<Task>
{
MakeCall1Async(data,timeTaken),
MakeCall2Async(data, timeTaken),
MakeCall3Async(data, timeTaken)
};
Task.Run(async () =>
{
await Task.WhenAll(tasks);
LogTimeTaken(timeTaken);
});
//finish webapi action and return
这是有效的方法:
//inside webapi action
Task.Run(async () =>
{
var tasks = new List<Task>
{
MakeCall1Async(data, timeTaken),
MakeCall2Async(data, timeTaken),
MakeCall3Async(data, timeTaken)
};
await Task.WhenAll(tasks).ContinueWith(t => LogTimeTaken(timeTaken));
});
//finish webapi action and return
为什么?
另外,我知道在 webapi 内部使用 fire and forget 的风险,并且它不会总是运行完成(例如当应用程序池回收时)。在这种情况下,95% 以上就足够了。
编辑
我理解大家对技术选择的担忧。我可能正在更改为发布/订阅架构或使用 QueueBackgroundWorkItem。鉴于我只需要 95% 的时间成功完成,我认为按照我的方式运行它就可以了。我试图得到的真正答案是为什么第一种方法失败而第二种方法成功写入日志。
【问题讨论】:
-
timeTaken是一个类实例,具有timeTakenForCall1InMs等长属性。该值在 Call1Async 结束时添加。
-
@DougJones,你也知道QueueBackgroundWorkItem吗?
-
@Noseratio 我确实看到了Stephen Cleary's blog post。它需要将所有开发盒和服务器升级到 4.5.2。这不是不可能的,但更新它是一件大事。
-
@DougJones,如果升级到 4.5.2 不可行,您仍然可以使用斯蒂芬所述的
IRegisteredObject。您不能只在 ASP.NET 下拥有未注册的“幽灵”即发即弃任务,跨越单个 HTTP 请求/响应的生命周期。
标签: c# asp.net-web-api async-await