如何在Azure函数中实现指数退避?

时间:2018-06-12 13:04:25

标签: c# .net azure azure-functions serverless

如何在Azure功能中实现指数退避?

我有一个依赖外部API的功能。我想使用重试策略来处理此服务的不可用性。 当队列中出现新消息时会触发此功能,在这种情况下,默认情况下会启用此策略:

  

对于大多数触发器,在函数执行期间发生错误时没有内置重试。具有重试支持的两个触发器是Azure Queue存储和Azure Blob存储。默认情况下,这些触发器最多重试五次。在第五次重试之后,两个触发器都将消息写入特殊的毒性队列。

不幸的是,在异常(TimeSpan.Zero)之后立即重试,这在这种情况下毫无意义,因为该服务很可能仍然不可用。 有没有办法动态修改邮件在队列中再次可用的时间?

我知道我可以设置visibilityTimeouthost.json reference),但它是为所有队列设置的,这不是我想在这里实现的。

我找到了一个解决方法,但它远非理想的解决方案。如果发生异常,我们可以再次将消息添加到队列中,并为此消息设置visibilityTimeout:

[FunctionName("Test")]
public static async Task Run([QueueTrigger("queue-test")]string myQueueItem, TraceWriter log,
    ExecutionContext context, [Queue("queue-test")] CloudQueue outputQueue)
{
    if (true)
    {
        log.Error("Error message");
        await outputQueue.AddMessageAsync(new CloudQueueMessage(myQueueItem), TimeSpan.FromDays(7),
            TimeSpan.FromMinutes(1), // <-- visibilityTimeout
            null, null).ConfigureAwait(false);
        return;
    }
}

不幸的是,这个解决方案很弱,因为它没有上下文(我不知道它是哪个尝试,因此我不能限制调用次数和修改时间(指数退避))。

内部重试政策也不受欢迎,因为它可以大幅增加成本(定价模型)。

3 个答案:

答案 0 :(得分:1)

我遇到了类似的问题,最终使用了内置了automatic retry功能的持久功能。当您将外部API调用包装到活动中时,可以使用此方法,并且在调用此活动时,可以通过options对象配置重试行为。您可以设置以下选项:

最大尝试次数:最大重试次数。

第一次重试间隔:第一次尝试重试之前要等待的时间。

退避系数:用于确定退避增量的系数。默认为1。

最大重试间隔:两次重试之间要等待的最长时间。

重试超时:进行重试所花费的最长时间。默认行为是无限期重试。

句柄:可以指定用户定义的回调以确定是否应重试函数。

答案 1 :(得分:1)

微软在 2020 年 11 月左右(预览版)添加了 retry policies,支持指数退避:

[FunctionName("Test")]
[ExponentialBackoffRetry(5, "00:00:04", "00:15:00")] // retries with delays increasing from 4 seconds to 15 minutes
public static async Task Run([QueueTrigger("queue-test")]string myQueueItem, TraceWriter log, ExecutionContext context)
{
    // ...
}

答案 2 :(得分:0)

要考虑的一个选项是让您的函数调用一个延迟设置为所需时间的逻辑应用程序,然后在延迟再次调用该函数之后。您还可以使用某些持久性存储将其他重试逻辑(如尝试次数)添加到逻辑应用程序,以计算您的尝试次数。如果存在连接问题,您只会调用Logic App。

或者,您可以将流程起点转换为逻辑应用程序,因为它也可以触发(思考绑定)队列消息。在任何一种情况下,Logic Apps都会添加暂停和重新调用功能和/或流程的功能。