У меня есть функция Azure, которая запускается очередью служебной шины. Если функция завершается сбоем, она немедленно повторяется (через 1 с) до 10 раз. Однако я хотел бы повторять попытку каждые пять минут. Даже после прочтения документации мне было неясно, как это должно быть реализовано.
[Function("Foo")]
public async Task Run(
ServiceBusTrigger("FooQueue",
Connection = "ServiceBusConnection")]
Foo foo,
int deliveryCount,
DateTime enqueuedTimeUtc,
string messageId)
В документации говорится, что поведение повторной попытки можно настроить в файле host.json
. Однако там также говорится, что настройки clientRetryOptions применяются только к взаимодействию со службой служебной шины. Они не влияют на повторные попытки выполнения функций.
При этом я не нашел в очереди служебной шины настройки, с помощью которой можно настроить поведение повтора.
Каков «официальный» способ реализации стратегии повторных попыток? Предполагается ли это реализовать в самой функции, используя задержки типа Task.Delay
вместе с параметром DeliveryCount
?
Как вы уже узнали, триггер служебной шины может выполнять немедленные повторные попытки только с помощью MaxDeliveryCount
. Отложенные повторы не поддерживаются ни пакетом SDK для функций, ни служебной шиной Azure.
Для отложенных повторных попыток с функциями изолированного Worker SDK вы можете реализовать собственное решение, доступное с помощью опции промежуточного программного обеспечения, которую поддерживает новый Functions SDK. Я изложил эту идею в блоге . Версия TLDR предназначена для использования счетчика доставки для немедленных повторных попыток и выдачи клонированного сообщения для отложенных повторных попыток, используя заголовки сообщений для отслеживания повторных попыток.
В чем был бы недостаток, если бы я просто добавил Task.Delay(TimeoutAfterError
) в блок Catcb самой функции? Я знаю, что у меня все еще будет проблема с общими ошибками в DLQ, но для единственной цели реализации задержки этого будет достаточно, не так ли?
Подход с задержкой может привести к тому, что у вас закончится время блокировки, что приведет к повторной доставке сообщения. Допустим, настроена очередь на блокировку на 1 минуту. Вашей функции потребовалось 35 секунд для обработки сообщения, но она не удалась, а отложенная повторная попытка настроена на выполнение через 15 секунд. Выглядит нормально, но это не так. Блокировка сообщения длится 60 секунд, из которых 50 секунд уже были израсходованы, и когда будет выполнена попытка обработки после задержки, сообщение будет разблокировано и обработано другим экземпляром. Вы могли бы пройти до 5 минут блокировки, но она вас догонит.
Еще одно ограничение, о котором следует помнить, — это время выполнения функции. Если вы придерживаетесь плана потребления, есть жесткая остановка. Одна отложенная повторная попытка может не сработать для всех сценариев, поэтому вам может потребоваться выполнить откат несколько раз и использовать не линейное, а экспоненциальное время. Когда вы проходите через различные сценарии, подход Task.Delay()
, хотя и применимый для конкретного сценария, становится неустойчивым во многих других сценариях.
Ах да, имеет смысл. Большое спасибо за ваше объяснение.
Эй, спасибо за ваш ответ. Я прочитал ваш пост в блоге. Чтобы разобрать это: - Вы создаете свою собственную очередь ошибок вместо встроенной очереди недоставленных писем, потому что таким образом вы можете сохранить фактическую ошибку (исключение). - Вы реализуете отложенную повторную попытку, используя
ScheduleMessageAsync
Кстати: в вашем сообщении в блоге было бы полезно включить недостающие методы расширенияCloneForError
иCreateSenderFor
. В остальном отличный пост, еще раз спасибо за помощь.