为啥 Task.Delay 不能在 Azure Function App 中工作?

Posted

技术标签:

【中文标题】为啥 Task.Delay 不能在 Azure Function App 中工作?【英文标题】:Why isn't Task.Delay working in an Azure Function App?为什么 Task.Delay 不能在 Azure Function App 中工作? 【发布时间】:2021-10-13 23:54:22 【问题描述】:

我有一个 C# 函数应用程序 (.net Core 3.1),用于处理队列中的项目。我需要放慢处理速度,因为我需要与另一个外部 API 通信,而且它的速率有限。

我正在使用

await Task.Delay(1000);

在调用 API 之间暂停函数应用一段时间。在我的本地开发环境中,它可以完美运行并在给定的时间段内暂停。部署到 Azure 时,似乎不会出现延迟,并且队列项目的处理速度比预期的要快得多。

我已经用 10000 毫秒(10 秒)的长时间进行了尝试,并且在本地测试时可以看到延迟,但是当部署到 Azure 时,队列项目很快就用完了,而且相隔不到 10 秒。

函数声明如下所示:

[FunctionName("ProcessUserQueue")]
public async Task RunAsync([QueueTrigger(QueueNames.ProcessUserQueueName)]string myQueueItem, ILogger log)

    log.LogInformation($"ProcessUserQueue trigger function processed: myQueueItem");
    await _userService.ProcessUserAsync(myQueueItem, log);

在 ProcessUserAsync 内部,我做的第一件事就是调用

await Task.Delay(10000);

它可以工作,但仅限于本地开发环境。

我的 host.json 看起来像这样(队列批量大小为 1):


  "version": "2.0",
  "functionTimeout": "00:10:00",
  "extensions": 
    "queues": 
      "batchSize": 1,
      "maxDequeueCount": 5
    
  

关于为什么这不起作用,或者如何更好地限制函数内 API 调用的速度的任何想法?

【问题讨论】:

收到消息后,新函数实例可以运行RunAsync。这些实例彼此不知道。 使用Task.Delay 对 API 的请求进行速率限制就像使用勺子试图拯救 泰坦尼克号 彼得,我想你已经明白了。我使用了其中一篇相关帖子,发现了 WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT = 1 的应用程序设置,这应该将应用程序限制为一个实例。这似乎有点帮助,但并不完全。然后我还修改了 host.json 以包含“newBatchThreshold”:0。函数应用程序现在似乎表现得很好。还需要做更多的测试。 【参考方案1】:

有多种方法可以延迟进程:

    您可以使用Thread.Sleep(),而不是使用Task.Delay()

    Task.Delay() 用于在不阻塞当前线程的情况下进行逻辑延迟。

    Thread.Sleep()用于阻塞当前线程。

    可以使用durable functions实现进程延时Reference

    它包括设置一个 initialVisibilityDelay : Add message

对于initialVisibilityDelay,您需要添加一个临时队列,然后添加一个函数。

更多请参考info

【讨论】:

【参考方案2】:

我不认为在读取队列时向 HttpTrigger 函数添加延迟在实际场景中不起作用,因为如果项目的处理时间超过函数超时期限,该函数将超时。

对于耗时超过 HttpTrigger 函数超时时间的操作,请使用 Azure Durable Functions

Durable Functions 提供了持久的计时器,用于编排器函数以实现延迟或设置异步操作的超时。

[FunctionName("BillingIssuer")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)

    for (int i = 0; i < 10; i++)
    
        DateTime deadline = context.CurrentUtcDateTime.Add(TimeSpan.FromDays(1));
        await context.CreateTimer(deadline, CancellationToken.None);
        await context.CallActivityAsync("SendBillingEvent");
    

有关使用计时器在 Azure Durable 函数中实现延迟,请参阅文章:https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-timers?tabs=csharp

有关 Azure 持久功能,请参阅:https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview?tabs=csharp

【讨论】:

以上是关于为啥 Task.Delay 不能在 Azure Function App 中工作?的主要内容,如果未能解决你的问题,请参考以下文章

如果 Task.Delay 优于 Thread.Sleep,为啥本书中的示例使用 Thread.Sleep?

REST API 中的 Thread.sleep 与 Task.delay

C#中的Task.Delay()和Thread.Sleep()区别

等待 Task.Delay() 与 Task.Delay().Wait()

Thread.Sleep(2500) 与 Task.Delay(2500).Wait()

为啥不能配置 Azure 诊断以通过新的 Azure 门户使用 Azure 表存储?