为啥 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()