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

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

Завершение

Чем ack, drop, retry и retry_after становятся в MQTT: одним подтверждением при QoS 1 и 2, ничем при QoS 0 и копиями, которые публикует рантайм.

Каждый исход обработчика на доставке с QoS 1 или QoS 2: что отправляет доставка и что происходит дальшеОбработчикОтправленоЗатемack()PUBACKPUBRECготовоdrop()PUBACKPUBRECготово,сообщениеотпущеноretry()ничеговернётся привозобновлениисессииretry()при пределеPUBACKPUBRECкопияпубликуетсясразуretry_after(d)PUBACKPUBRECкопияпубликуетсячерез dнет исхода:пакет отпущенничегокак retry():вернётся привозобновленииПри QoS 0 ничего не отправляется, ack и dropвозвращают AckError::Unsupported, а копия рантайма уходит
Схема текстом
  1. Обработчик: ack(); drop(); retry(); retry() при пределе; retry_after(d); нет исхода: пакет отпущен
  2. Отправлено: PUBACK PUBREC; PUBACK PUBREC; ничего; PUBACK PUBREC; PUBACK PUBREC; ничего; При QoS 0 ничего не отправляется, ack и drop возвращают AckError::Unsupported, а копия рантайма уходит
  3. Затем: готово; готово, сообщение отпущено; вернётся при возобновлении сессии; копия публикуется сразу; копия публикуется через d; как retry(): вернётся при возобновлении
  4. ack() → PUBACK PUBREC
  5. PUBACK PUBREC → готово
  6. drop() → PUBACK PUBREC
  7. PUBACK PUBREC → готово, сообщение отпущено
  8. retry() → ничего
  9. ничего → вернётся при возобновлении сессии
  10. retry() при пределе → PUBACK PUBREC
  11. PUBACK PUBREC → копия публикуется сразу
  12. retry_after(d) → PUBACK PUBREC
  13. PUBACK PUBREC → копия публикуется через d
  14. нет исхода: пакет отпущен → ничего
  15. ничего → как retry(): вернётся при возобновлении

У MQTT есть один ответ на доставку - подтверждение: PUBACK при QoS 1, PUBREC при QoS 2. ack отправляет его. drop тоже отправляет его, потому что подтверждение - единственный способ, которым протокол позволяет сервису закончить с сообщением.

В MQTT нет отрицательного подтверждения, поэтому на живом соединении сервер никогда не отправляет сообщение повторно. retry() без объявлений возвращает AckError::Unsupported, рантайм записывает это в журнал, а доставка остаётся неподтверждённой. Сервер отправляет её повторно, только когда постоянная сессия возобновляется на новом соединении. До тех пор она занимает один слот в окне Receive Maximum: когда окно заполнено такими доставками, сервер не отправляет по соединению новых сообщений с QoS 1 и QoS 2. Пакет, который обработчик отпустил, так же остаётся неподтверждённым.

Переобработка в пределах сессии - это копия, которую публикует рантайм. retry_after(d) подтверждает оригинал, ждёт d и публикует копию. retry() при объявленном пределе или теме для недоставленных сообщений публикует копию сразу. У доставки с QoS 0 подтверждать нечего, а её копия всё равно уходит.

ИсходQoS 0
ack, dropAckError::Unsupported
retry()AckError::Unsupported; при объявленном пределе копия публикуется сразу
retry_after(d)копия публикуется через d
нет исходаничего

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

Переобработка в MQTT: предел попыток, посчитанный в заголовке рантайма, выбирает между копией и темой для недоставленных сообщенийНиже пределаНа пределеДоставканомер попытки читается из x-ruststream-retry-countОбработчик возвращаетretry_after(d) или retry() при объявленииmax_attempts: эта попытка ниже предела?Оригиналподтверждён,копия ждёт dMqttTopic:копия уходитв его темуMqttFilter:в тему, которуюназывает точкамонтированияТема длянедоставленных:доставкапубликуется тудаБез темы длянедоставленных:подтвержденаи отпущенаКопия - обычная публикация: её получает каждаяподписка, фильтр которой подходит к её теме.Копию, ждущую задержки, держит процесс, и падениедо срабатывания таймера её теряет.
Схема текстом
  1. Ниже предела: Оригинал подтверждён, копия ждёт d; MqttTopic: копия уходит в его тему; MqttFilter: в тему, которую называет точка монтирования
  2. На пределе: Тема для недоставленных: доставка публикуется туда; Без темы для недоставленных: подтверждена и отпущена
  3. Доставка номер попытки читается из x-ruststream-retry-count → Обработчик возвращает retry_after(d) или retry() при объявлении: обработана
  4. Обработчик возвращает retry_after(d) или retry() при объявлении → max_attempts: эта попытка ниже предела?: переобработка
  5. max_attempts: эта попытка ниже предела? → Ниже предела: ниже
  6. max_attempts: эта попытка ниже предела? → На пределе: на пределе
  7. Копия - обычная публикация: её получает каждая подписка, фильтр которой подходит к её теме. Копию, ждущую задержки, держит процесс, и падение до срабатывания таймера её теряет.

Предел объявляется в точке монтирования через max_attempts, и первая доставка считается первой попыткой. MQTT сам не считает доставки, поэтому рантайм считает опубликованные копии в заголовке каждой копии x-ruststream-retry-count.

Ниже предела копия уходит по адресу, который даёт форма подписки. MqttTopic, в том числе совместный, указывает на собственную тему, поэтому его регистрация ничего не называет. MqttFilter подходит ко многим темам и не публикует ни в одну из них, поэтому его регистрация называет тему для копии: один раз или для каждой доставки через преобразование. Если регистрация фильтра не называет тему ни одним из этих способов, приложение не запускается.

На пределе доставка уходит в тему для недоставленных сообщений с неизменной полезной нагрузкой. Если тема для недоставленных сообщений не объявлена, доставка подтверждается и отпускается.

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