我正在构建一个ASP.NET应用程序。该应用程序显示来自第三方WebAPI的结果。如果WebAPI花费2秒钟以上,它将返回缓存的结果。
下面的代码创建两个async
任务,一个任务调用WebAPI,另一个任务从缓存中检索。它还有一个计时器任务。如果Web任务在不到2秒的时间内完成,则返回其结果。如果计时器任务首先结束,或者Web任务有异常,则返回缓存的结果。该代码到目前为止运行良好。
public async Task<ActionResult> Index()
{
Task<string> readFromCacheTask = ReadFromCacheAsync();
Task<string> readFromWebTask = ReadFromWebAsync();
try
{
Task timerTask = Task.Delay(2000);
Task completedTask = await Task.WhenAny(readFromWebTask, timerTask);
await completedTask;
if (readFromWebTask.Status == TaskStatus.RanToCompletion)
{
return Content(readFromWebTask.Result);
}
}
catch (Exception)
{
// Return cache result if there is an error getting from web.
}
return Content(await readfromCacheTask);
}
问题:我还希望允许Web任务继续运行,即使在将缓存的结果返回给调用者之后也是如此,以便可以将更新的Web结果缓存起来并用于下一个来电者。
我想到的是使用Task.Run
中的Application_Start
产生一个异步后台线程。该线程包含一个任务集合,并在连续循环中运行。调用控制器时,它将创建一个readFromWebTask并将其添加到后台线程中的任务集合中。
这是一个好方法吗?有没有更好的方法来实现?
澄清@ 2019-02-27 14:46 :readFromWebTask包含用于更新缓存的逻辑。从运行时观察,ASP.NET不允许readFromWebTask运行超过请求完成时间。任务已中止,并且没有运行到最后。在下面的示例中,仅Foo被写入了文本文件。酒吧不在那里。
public class HomeController : Controller
{
public async Task DelayAndLog()
{
string path = @"C:\temp\test.txt";
System.IO.File.AppendAllText(path, string.Format("{0}: Foo", DateTime.Now));
await Task.Delay(2000);
System.IO.File.AppendAllText(path, string.Format("{0}: Bar", DateTime.Now));
}
public async Task<ActionResult> Index()
{
Task a = DelayAndLog();
await Task.Delay(1);
return Content("Hello World");
}
}