Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.
Завершение
Что ack, drop, retry и retry_after записывают в таблицу очереди в каждой форме захвата и
как счётчик попыток и dead letter превращают переобработку в перемещение.
Схема текстом
- Исход обработчика: ack, drop, retry(), retry_after(d) или dead letter на пределе → В транзакционном режиме любой исход, кроме ack, сначала откатывает записи обработчика
- В транзакционном режиме любой исход, кроме ack, сначала откатывает записи обработчика → Оператор таблицы для исхода, свой или диалекта: UPDATE, DELETE или перемещение в dead letter
- Оператор таблицы для исхода, свой или диалекта: UPDATE, DELETE или перемещение в dead letter → Блокировка строк: в транзакции захвата, затем COMMIT
- Оператор таблицы для исхода, свой или диалекта: UPDATE, DELETE или перемещение в dead letter → Аренда: только пока строка держит аренду этой доставки
- Оператор таблицы для исхода, свой или диалекта: UPDATE, DELETE или перемещение в dead letter → Блокировка ключа: на соединении ключа, затем снятие
- Отброшена без завершения: транзакция откатывается, аренда освобождается, блокировка уходит с соединением
| Исход | Блокировка строк | Аренда | Рекомендательная блокировка |
|---|---|---|---|
ack, drop | DELETE или установка 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 вместо оператора
диалекта, в той же транзакции или на том же соединении.
Переобработка
Схема текстом
- Строка в работе, её столбец attempt считает доставки → Обработчик возвращает retry() или retry_after(d): обработано
- Обработчик возвращает retry() или retry_after(d) → max_attempts: достигла ли попытка предела?: просит снова
- max_attempts: достигла ли попытка предела? → Ниже предела: строка возвращается с ещё одной попыткой, сразу или после retry_after: ниже
- max_attempts: достигла ли попытка предела? → На пределе: строка перемещается в свою группу или таблицу dead letter: на пределе
- Задержка - столбец строки: она переживает перезапуск, а копия сообщения никогда не публикуется
Таблица очереди сама считает свои доставки: столбец 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.