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

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

Завершение

Что ack, drop, retry и retry_after записывают в таблицу очереди в каждой форме захвата и как счётчик попыток и dead letter превращают переобработку в перемещение.

Завершение: исход выбирает оператор, транзакционный режим откатывает записи обработчика, если тот не подтвердил доставку, а оператор выполняется там, где форма держит строкуИсход обработчика: ack, drop, retry(),retry_after(d) или dead letter на пределеВ транзакционном режиме любой исход, кроме ack,сначала откатывает записи обработчикаОператор таблицы для исхода, свойили диалекта: UPDATE, DELETE илиперемещение в dead letterБлокировкастрок: втранзакциизахвата, затемCOMMITАренда: толькопока строкадержит арендуэтой доставкиБлокировкаключа: насоединенииключа, затемснятиеОтброшена без завершения: транзакция откатывается,аренда освобождается, блокировка уходит с соединением
Схема текстом
  1. Исход обработчика: ack, drop, retry(), retry_after(d) или dead letter на пределе → В транзакционном режиме любой исход, кроме ack, сначала откатывает записи обработчика
  2. В транзакционном режиме любой исход, кроме ack, сначала откатывает записи обработчика → Оператор таблицы для исхода, свой или диалекта: UPDATE, DELETE или перемещение в dead letter
  3. Оператор таблицы для исхода, свой или диалекта: UPDATE, DELETE или перемещение в dead letter → Блокировка строк: в транзакции захвата, затем COMMIT
  4. Оператор таблицы для исхода, свой или диалекта: UPDATE, DELETE или перемещение в dead letter → Аренда: только пока строка держит аренду этой доставки
  5. Оператор таблицы для исхода, свой или диалекта: UPDATE, DELETE или перемещение в dead letter → Блокировка ключа: на соединении ключа, затем снятие
  6. Отброшена без завершения: транзакция откатывается, аренда освобождается, блокировка уходит с соединением
ИсходБлокировка строкАрендаРекомендательная блокировка
ack, dropDELETE или установка processed_at, затем COMMITто же, WHERE locked_until равен токену доставкито же, на соединении доставки, затем снятие блокировки
retry()attempt = attempt + 1, затем COMMIT; без столбца attempt - откатlocked_until = NULLоператора нет: строку возвращает снятие блокировки
retry_after(d)более поздний retry_after, attempt + 1более поздний retry_after, locked_until = NULLболее поздний retry_after, затем снятие блокировки
предел достигнутгруппа строки меняется на группу dead letter, или строка перемещается в таблицу dead letterто же, аренда сбрасываетсято же, затем снятие блокировки
отброшена без завершенияоткатаренда сразу освобождаетсяблокировка снята, соединение закрыто

Форма решает, что держит строку, поэтому решает и то, где выполняется оператор. В форме блокировки строк оператор выполняется в транзакции захвата, и её фиксация и есть завершение: строка и её исход меняются вместе. В форме аренды каждый оператор содержит токен доставки - срок, который записал её захват, - и затрагивает строку, только пока строка этот токен держит. Завершение, которое находит другой токен, возвращает ошибку SqlxBrokerError::LeaseLost, и строка принадлежит захвату, который взял её позже. В форме рекомендательной блокировки оператор фиксируется сам по себе на соединении, которое держит ключ, а затем блокировка снимается. Оператор, вернувший там ошибку, всё равно снимает блокировку, и строка возвращается в прежнем виде.

drop завершает строку так же, как ack: отравленное сообщение уходит из очереди. Таблица без столбца retry_after принимает retry_after(d) как retry() и пишет предупреждение в журнал. Собственное событие сервиса, названное через custom(..), выполняет свой SQL вместо оператора диалекта, в той же транзакции или на том же соединении.

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

Переобработка в таблице очереди: строка считает свои попытки, а предел решает, вернуть строку или переместить её в dead letterСтрока в работе, её столбец attemptсчитает доставкиОбработчик возвращает retry() или retry_after(d)max_attempts: достигла ли попытка предела?Ниже предела: строкавозвращается с ещёодной попыткой, сразуили после retry_afterНа пределе: строкаперемещается в своюгруппу или таблицуdead letterЗадержка - столбец строки: она переживает перезапуск,а копия сообщения никогда не публикуется
Схема текстом
  1. Строка в работе, её столбец attempt считает доставки → Обработчик возвращает retry() или retry_after(d): обработано
  2. Обработчик возвращает retry() или retry_after(d) → max_attempts: достигла ли попытка предела?: просит снова
  3. max_attempts: достигла ли попытка предела? → Ниже предела: строка возвращается с ещё одной попыткой, сразу или после retry_after: ниже
  4. max_attempts: достигла ли попытка предела? → На пределе: строка перемещается в свою группу или таблицу dead letter: на пределе
  5. Задержка - столбец строки: она переживает перезапуск, а копия сообщения никогда не публикуется

Таблица очереди сама считает свои доставки: столбец attempt. Форма блокировки строк считает их в операторе, который возвращает строку, форма аренды - при захвате, форма рекомендательной блокировки - при взятии строки. Обработчик читает счётчик через Ctx<keys::Attempt>, поэтому сам вычисляет свою отсрочку: политики отсрочки в крейте нет.

Предел и место назначения задаются вместе в точке монтирования: max_attempts(n) и dead_letter(..). Переобработка или retry_after строки, попытка которой достигла предела, вместо этого перемещает строку и пишет предупреждение в журнал. В таблице с группами dead letter - это группа, и перемещение - один UPDATE группы строки. В таблице без групп это другая таблица с теми же столбцами: на PostgreSQL один оператор, WITH moved AS (DELETE .. RETURNING ..) INSERT .. SELECT; на MySQL, MariaDB и SQLite копирование, затем удаление, в одной транзакции. max_attempts(1) перемещает строку при первой же неудаче.

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

Outbox тоже завершает свои записи по исходу обработчика, на стороне получателя: подтверждение и drop отмечают запись, а переобработка оставляет её до следующего старта, как показывает страница Outbox.