I am building an ASP.NET application. The application displays result from a third-party WebAPI. If the WebAPI takes more than 2 seconds, it will return the cached result.
The code below creates two async
tasks, one for calling the WebAPI and one for retrieving from the cache. It also has a timer task. If the web task completes in less than 2 seconds, its result is returned. If the timer task ends first or the web task has an exception, the cached result is returned. The code runs so far so good.
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);
}
Question: What I want in addition is allowing the web task to continue running even after the cached result is returned to the caller so that an updated web result will be cached and will be available for the next caller.
What I have in mind is spawning an async background thread using Task.Run
in Application_Start
. The thread contains a task collection and runs in a continuous loop. When the controller is called, it creates a readFromWebTask and adds it to the task collection in the background thread.
Is this a good approach? Are there better ways to achieve?
Clarification @2019-02-27 14:46: The readFromWebTask contains the logic for updating the cache. From the run-time observation, ASP.NET does not let readFromWebTask to run past the request completion. The task was aborted and did not run to the end. In following example, only Foo was written in the text file. Bar is not there.
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");
}
}