Azure 函数可见性超时

Azure function visibilityTimeout

当我阅读有关 visibilityTimeout 的文档时:https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue#host-json 它说 "The time interval between retries when processing of a message fails."。我的理解是,如果超时设置为 30 秒并且我的函数运行了 1 分钟但在这 1 分钟内没有失败,则消息不会对队列中的其他人可见。但是当我通过其他来源 (Whosebug fx) 阅读它时,它告诉我相反的情况,当函数的执行时间超过超时时,即使函数仍在处理消息,消息也会变得可见。

真相是什么?超时是否仅在函数不再 运行 时才相关(并且可能已经失败),或者即使函数仍然是 运行,消息是否会再次可见?

没有意义的是,如果我们假设消息在达到超时时变得可见,那么默认超时是 00:00:00,这意味着消息在它出现的同时可见出列。这与 3. 党派人士所说的相矛盾。

我对此有点困惑。

我已经用

测试过这个
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage.Queue;

namespace WorkerFunctions
{
    public static class WorkerFunctions
    {
        [FunctionName("WorkerFunction1")]
        public static async Task Function1(
            [QueueTrigger("outputQueue")]
            CloudQueueMessage item,
            [Queue("outputQueue")]
            CloudQueue outputQueue,
            DateTimeOffset nextVisibleTime,
            DateTimeOffset expirationTime,
            DateTimeOffset insertionTime,
            ILogger log)
        {
            log.LogInformation("########## Function 1 ###############");
            log.LogInformation($"NextVisibleTime: {nextVisibleTime}");
            log.LogInformation($"NextVisibleTime: {(nextVisibleTime-insertionTime).TotalSeconds}");
            log.LogInformation($"C# Queue trigger function processed: {item.AsString}");

            Thread.Sleep(TimeSpan.FromMinutes(20));
        }

        [FunctionName("WorkerFunction2")]
        public static async Task Function2(
            [QueueTrigger("outputQueue")]
            CloudQueueMessage item,
            [Queue("outputQueue")]
            CloudQueue outputQueue,
            DateTimeOffset nextVisibleTime,
            DateTimeOffset expirationTime,
            DateTimeOffset insertionTime,
            ILogger log)
        {
            log.LogInformation("########## Function 2 ###############");
            log.LogInformation($"NextVisibleTime: {nextVisibleTime}");
            log.LogInformation($"NextVisibleTime: {(nextVisibleTime - insertionTime).TotalSeconds}");
            log.LogInformation($"C# Queue trigger function processed: {item.AsString}");

            Thread.Sleep(TimeSpan.FromMinutes(20));
        }
    }
}

有了这个主机文件

{
  "version": "2.0",
  "extensions": {
    "queues": {
      "maxPollingInterval": "00:00:02",
      "visibilityTimeout": "00:00:10",
      "batchSize": 16,
      "maxDequeueCount": 5,
      "newBatchThreshold": 8
    }
  }
}

当我将一条简单消息放入队列并让它 运行 时,我看到以下内容:

  1. 抓住它的函数,在睡眠结束前不会释放它
  2. 我在日志中看不到租约已续订,但它似乎是在幕后发生的

这告诉我什么:

  1. 如果函数没有失败,或者主机没有失败,那么租约将根据以下条件自动续订:
  2. 当达到可见性超时且函数为 运行ning 时,消息不会 "readded" 进入队列
  3. 关于 visibilityTimeout 的文档是真实的:"The time interval between retries when processing of a message fails."(来自 https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue#hostjson-settings

我没有保存任何与此相矛盾的 3.party 链接(抱歉,我没有保存这些链接),但它们存在。我希望有人能回答这个问题,这样我就可以得到澄清。

这里似乎实际上使用了两个不同的可见性超时值。两者都由 Azure WebJobs SDK 设置,但只有一个是可配置的。

当函数失败时

queues.visibilityTimeout 配置选项更恰当地命名为 retryDelay

当函数抛出异常或因其他类型的错误而失败时,消息将返回到队列中以供重试。该消息与配置的 visibilityTimeout(参见 here)一起返回,这会延迟函数下一次尝试 运行.

的时间

这使您的应用程序能够处理暂时性错误。例如,如果电子邮件 API 或其他外部服务暂时关闭。通过延迟重试,服务有可能重新联机以进行下一次功能尝试。

重试限制为 maxDequeueCount 次尝试(默认为 5 次),然后将消息移至 Poison Queue

虽然函数是运行宁

QueueTrigger 绑定 运行 函数时,它将消息出列,可见性超时为 10 分钟(hard-coded here). It then sets a timer to extend the visibility window when it reaches half-time as long as the function is running (see the timer and visibility update 在源中)。

通常您不需要担心这个,只要您的函数正确使用 CancellationTokens 即可。仅当 Azure Function/WebJob 主机没有到达 shut down gracefully 时,这 10 分钟的超时才有意义。例如:

因此,只要函数仍然是 运行ning,消息就会在队列中保持隐藏状态。

验证

我做了一个类似的实验来检查:

[FunctionName("SlowJob")]
public async Task Run(
    [QueueTrigger("slow-job-queue")] CloudQueueMessage message,
    ILogger log)
{
    for (var i = 0; i < 20; i++)
    {
        log.LogInformation($"Next visible {i}: {message.NextVisibleTime}");
        await Task.Delay(60000);
    }
}

输出:

Next visible 0: 5/11/2020 7:49:24 +00:00
Next visible 1: 5/11/2020 7:49:24 +00:00
Next visible 2: 5/11/2020 7:49:24 +00:00
Next visible 3: 5/11/2020 7:49:24 +00:00
Next visible 4: 5/11/2020 7:49:24 +00:00
Next visible 5: 5/11/2020 7:54:24 +00:00
Next visible 6: 5/11/2020 7:54:24 +00:00
Next visible 7: 5/11/2020 7:54:24 +00:00
Next visible 8: 5/11/2020 7:54:24 +00:00
Next visible 9: 5/11/2020 7:54:24 +00:00
Next visible 10: 5/11/2020 7:59:24 +00:00
Next visible 11: 5/11/2020 7:59:24 +00:00
...