ASP.NET:当控制器在快速运行的任务上退出时,异步执行对较慢运行的任务的回调

问题描述

我有一个 ASP.NET 控制器,它在内部调用 API 和缓存以获取答案,并从完成的第一个任务中返回答案。一般来说,API比缓存慢很多,缓存在50ms内返回,而API在第95个百分位2秒内返回。

要求:

  1. 如果可用,立即从缓存中返回答案。否则等待 API 并返回可用/空响应(视情况而定)。
  2. API 调用完成后,我们会使用新答案更新缓存(如果有)。

问题: 如何在不阻塞控制器的情况下等待 API 调用并在后台线程中写入缓存?

当前流量:

Task<string>[] getDataTasks = new Task<string>[]
{
    getDataFromAPI(),getDataFromCache()
};

var finishedTaskIndex = Task.WaitAny(getDataTasks);
var response = getDataTasks[finishedTaskIndex].Result;

if (finishedTaskIndex == 1 && string.IsNullOrEmpty(response))
{          
      response = await getDataTasks[0];
      writetoCacheTask(response); //fire and forget,this is non-blocking
}

**//Problem :- How to await for response from API and write to cache in a non-blocking manner** THIS DOES NOT WORK
Task.Run(async () =>
{
     var apiResponse = await getDataTasks[0];
     writetoCacheTask(apiResponse);
});

return response;

在上面,即使我使用一个新线程来等待独立于主线程的api调用,它也不起作用。

不起作用 尝试在任务上使用 ContinueWith 并带有 TaskContinuationoptions = ExecuteSynchronously 的回调,因为这会在调用任务的同一线程上继续。但我可能理解错了。

Task.Run(async () =>
{
    return await getDataTasks[0];
}).ContinueWith(this.CallBack,TaskContinuationoptions.ExecuteSynchronously);

有效:使用委托处理程序

// private members of controller
private delegate string DelegateHandler();

private string getDataFromAPisync()
{
   return getDataFromAPI().GetAwaiter().GetResults();
}

private string getDataFromCacheSync()
{
   return getDataFromCache().GetAwaiter().GetResults();
}

private void CallBack(IAsyncResult ar)
{
   var apiResponse = apiInvoker.EndInvoke(ar);
   writetoCacheTask(apiResponse);
}
// In controller
var apiInvoker = new DelegateHandler(this.getDataFromAPisync)
var cacheInvoker = new DelegateHandler(this.getDataFromCacheSync)

IAsyncResult apiResults = apiInvoker.BeginInvoke(this.CallBack,null);
IAsyncResult cacheResults = cacheInvoker.BeginInvoke(null,null);

var handles = new WaitHandle[]
{
   apiResults.AsyncWaitHandle,cacheResults.AsyncWaitHandle
}

WaitHandle.WaitAny(handles);

if (cacheResults.IsCompleted)
{
   return cacheInvoker.EndInvoke(ar);
}

return apiInvoker.EndInvoke(ar);

当我使用委托处理程序时,它看起来像用于进行 api 调用后台线程,也用于处理回调,并且只有在回调完成后它才会被终止。

如何使用任务库做同样的事情?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)