Перейти к основному содержимому
Нормативная версия документации - английская

Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.

Завершение

Чем ack, retry, retry_after и drop становятся в SQS: каждый исход - один вызов к очереди, а переобработка ждёт в самой очереди.

Каждый исход обработчика, вызов SQS, который он делает, и то, что происходит с сообщениемИсходВызов SQSРезультатackDeleteMessageУдаленоretry()ChangeMessageVisibility(0)Видно сразуretry_after(d)ChangeMessageVisibility(d)Вернётся через d,в пределах 12 чпосле полученияdropDeleteMessage;на пределе:Visibility(0)Удалено илиперенесенов DLQотброшенанезавершённойБез вызова,без продленияВернётся послетайм-аута
Схема текстом
  1. Исход: ack; retry(); retry_after(d); drop; отброшена незавершённой
  2. Вызов SQS: DeleteMessage; ChangeMessage Visibility(0); ChangeMessage Visibility(d); DeleteMessage; на пределе: Visibility(0); Без вызова, без продления
  3. Результат: Удалено; Видно сразу; Вернётся через d, в пределах 12 ч после получения; Удалено или перенесено в DLQ; Вернётся после тайм-аута
  4. ack → DeleteMessage
  5. DeleteMessage → Удалено
  6. retry() → ChangeMessage Visibility(0)
  7. ChangeMessage Visibility(0) → Видно сразу
  8. retry_after(d) → ChangeMessage Visibility(d)
  9. ChangeMessage Visibility(d) → Вернётся через d, в пределах 12 ч после получения
  10. drop → DeleteMessage; на пределе: Visibility(0)
  11. DeleteMessage; на пределе: Visibility(0) → Удалено или перенесено в DLQ
  12. отброшена незавершённой → Без вызова, без продления
  13. Без вызова, без продления → Вернётся после тайм-аута

retry_after(d) считает задержку в целых секундах с округлением вверх, поэтому сообщение никогда не возвращается раньше d. Задержка, которая выходит за 12 часов с момента получения, сокращается до их конца, и крейт пишет в журнал предупреждение с именем очереди. Доставка, которую отбросили без завершения, не делает вызова: её продление прекращается, и сообщение возвращается, когда истекает его текущий тайм-аут.

В SQS нет операции, которая отвергает сообщение, не удаляя его, поэтому drop удаляет сообщение. Исключение - очередь, регистрация которой объявляет политику перенаправления. Там доставка, полученная maxReceiveCount раз, возвращается в очередь, а не удаляется: в DLQ её переносит именно следующее получение, а удаление её бы потеряло.

redelivery_count доставки - это ApproximateReceiveCount очереди, и первая доставка считается первой. Он считает каждое получение, включая истёкший тайм-аут, а не только переобработки, которые запросил сервис.

Переобработка​

Переобработка в SQS: сообщение ждёт в очереди, а политика перенаправления решает при следующем полученииДоставкасчётчик получений показывает номер попыткиОбработчик возвращаетretry_after(d) или retry()ChangeMessageVisibility(d)сообщение ждёт в очередиСледующее получение: сообщение полученоуже maxReceiveCount раз?Ещё нет:доставляется повторното же сообщениеДа: SQS переноситего в DLQdrop на последнем допустимом получении возвращаетсообщение с видимостью 0: SQS переносит его, а не теряетЖдущее сообщение хранит очередь:падение сервиса не теряет ни одной переобработки
Схема текстом
  1. Доставка счётчик получений показывает номер попытки → Обработчик возвращает retry_after(d) или retry(): обработана
  2. Обработчик возвращает retry_after(d) или retry() → ChangeMessageVisibility(d) сообщение ждёт в очереди: переобработка
  3. ChangeMessageVisibility(d) сообщение ждёт в очереди → Следующее получение: сообщение получено уже maxReceiveCount раз?: через d
  4. Следующее получение: сообщение получено уже maxReceiveCount раз? → Ещё нет: доставляется повторно то же сообщение: ещё нет
  5. Следующее получение: сообщение получено уже maxReceiveCount раз? → Да: SQS переносит его в DLQ: да
  6. drop на последнем допустимом получении возвращает сообщение с видимостью 0: SQS переносит его, а не теряет
  7. Ждущее сообщение хранит очередь: падение сервиса не теряет ни одной переобработки

Переобработка никогда не покидает очередь. retry_after(d) делает сообщение невидимым на d, и оно возвращается тем же сообщением, с тем же идентификатором и счётчиком получений на единицу больше. Ничего не публикуется заново, поэтому запасной путь рантайма с повторной публикацией здесь не работает, и .out_retry(..) на SqsQueue не компилируется. Видимость, которая заканчивается позже 12 часов после получения, SQS отвергает.

max_attempts(n) и dead_letter(q) вместе образуют политику перенаправления очереди: maxReceiveCount равен n, а DLQ - q. Подписка записывает политику в очередь при открытии, и SQS сам считает получения и переносит исчерпавшее попытки сообщение. Одна половина без другой даёт ошибку SqsError::IncompleteRedrive при старте.

Ждущее сообщение хранит очередь, поэтому падение сервиса не теряет ни одной переобработки: сообщение возвращается, когда заканчивается его видимость, к тому потребителю, который опросит очередь следующим.