【问题标题】:Using Async/Await with Azure App Services Web API将 Async/Await 与 Azure 应用服务 Web API 结合使用
【发布时间】:2019-08-09 09:08:58
【问题描述】:

我有一个作为 Azure 应用服务托管的 .Net Web Api。 (我必须从 ADF 将其称为网络活动。)

这个 API 有一些代码可以运行很长时间,所以I want to make this Async

这就是我的测试方式:

[Route("apiA/[controller]")]
    [ApiController]
    public class AsynccallController : ControllerBase
    {

        [HttpPost]
        public async Task<String> PostA()
        {
            var strTask = await Longfunction();
            return strTask;
        }

        private Task<string> Longfunction()
        {
            Thread.Sleep(TimeSpan.FromSeconds(300));
            return Task.FromResult("value1");
        }

    }

邮递员的测试:

根据to this documentation,await 关键字应该在执行睡眠之前将控制权返回给调用者函数(在本例中为邮递员)。但我没有看到这种情况发生。它仍然等待这 300 秒向邮递员发送响应,这就像一个同步调用。为什么?

其次,如果它确实在“等待”时将控制权发回,那么 return 语句何时以及如何将值发回?

谢谢。

【问题讨论】:

  • await 确实将控制权(和 Task&lt;&gt; 对象)返回给调用者,但调用者(.NET Web API 运行时)不会将 HTTP 响应发送回客户端,直到该任务已完成。
  • 谢谢@noseratio 有没有办法在任务完成之前发回响应?我需要一种方法来触发并忘记那个 api 调用。我什至不需要得到任何回复。
  • 传统上您会使用HostingEnvironment.QueueBackgroundWorkItem 之类的东西,但我认为这在使用 Azure 托管时不起作用。也许,IApplicationLifetime 可以提供帮助。不是 Azure 专家,但我认为您应该使用 Azure 队列或 Azure Functions 等专用服务来运行即发即弃任务,您可以从 Web API 启动这些任务,然后在不等待结果的情况下返回。
  • 让任务在 HTTP 事务结束后持续存在通常不是一个好主意。当事务结束时,管道被拆除,您的大部分上下文将丢失、处置或处于无效状态。

标签: .net asp.net-web-api async-await azure-web-app-service azure-app-service-plans


【解决方案1】:
  1. 您几乎永远不想使用 Thread.Sleep() - Task.Delay() 在后台使用 Timer 并且是异步的(使线程能够执行其他工作),而 Thread.Sleep 阻塞!
  2. 您可以 - 假设 - 通过在 Longfunction() 调用之前省略 await 或使用 Task.Run(() =&gt; Longfunction()) 来“一劳永逸” - 请注意,这不是明智的做法,例如您的任务不受应用程序池回收的保护。
  3. 如果您想以正确的方式卸载长时间运行的操作,我非常建议您查看Hangfire

【讨论】:

  • 像在 Web API 中那样使用 Task.Run 是个坏主意,就像简单地以即发即弃的方式调用 Longfunction a 一样,而不观察它返回的 Task。想想如果你的 Web API 进程被拆除和回收会发生什么。请参阅我对 OP 问题的 cmets。
  • @noseratio - 因此引用了 Hangfire ;)
  • 以这种方式使用Task.Run() 绝对不是一个好的答案。
  • 如果我只是运行批处理作业,这仍然是个问题吗?如果它被杀死,我应该能够手动重新运行。
【解决方案2】:

这个 API 有一些运行时间很长的代码,所以我想把这个异步化。

该答案是推荐“异步模式”。具体来说,this asynchronous messaging pattern。此模式与 asyncawait 关键字无关。异步消息传递模式使用具有非常广泛定义的术语“异步”; async 关键字是异步的一种非常具体的实现,此处不适用。

要真正解决您的问题,您应该让您的操作方法生成请求 ID,将“请求”消息添加到可靠队列(例如 Azure 队列),并将请求 ID 返回给客户端。接下来,你需要一个独立的后台工作者;由于您的 Web 应用程序是 Azure 应用程序服务,您可能会发现 Azure Web Jobs 对于后台工作人员来说是一个不错的选择,但您也应该考虑使用 Azure Functions。最后,您需要一种方法让工作人员与您的前端进行通信,以便让其知道工作何时完成;这里有多种可能的方法,从 SignalR 到前端可以通过应用服务 API 轮询的某种共享“工作数据库”。

其次,如果它确实在“等待”时将控制权发回,那么 return 语句何时以及如何将值发回?

你是对的; HTTP 响应不能发回await,否则将无法将实际结果值作为响应发送。

根据本文档,await 关键字应将控制权返回给调用者函数(在本例中为邮递员)

这就是误解的所在。邮递员没有调用你的函数; ASP.NET 做到了。 await 正确让步给 ASP.NET,后者将该请求线程返回到线程池。在操作方法完成之前,ASP.NET完成请求。

【讨论】:

  • 感谢您的回复。我只需要运行一些每天生成一些文件的代码。 Web 作业似乎我必须管理底层架构并且更复杂,而 Azure 功能很有吸引力(无服务器等)。我读到它有超时问题。此外,文件的生成可以触发我的后续步骤,因此我不需要汇集或与调用者通信。
  • @Gadam:啊,如果您需要从 timer 而不是 HTTP 事件 运行它,那就更简单了。在这种情况下,我会推荐 Azure Functions;它内置了对计时器触发器的支持。消费计划上的 AF 最长超时为 10 分钟(功能,而不是错误); if you want infinite timeouts, use the App Service plan.
猜你喜欢
  • 2018-08-20
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 2015-12-25
  • 2021-11-18
  • 2021-06-25
  • 1970-01-01
  • 2020-08-27
相关资源
最近更新 更多