← Barcha maqolalar
Blog

Доставка после сбоя: outbox, повторы и идемпотентность без магических гарантий

Команда AiHummer6 daq o‘qish
Русский
“Доставка после сбоя: outbox, повторы и идемпотентность без магических гарантий” maqolasining muqovasi

Самый неприятный момент в интеграции находится между двумя событиями: приложение уже решило отправить ответ, но ещё не знает, принял ли его внешний канал. Если процесс упадёт здесь, простая повторная отправка может создать дубль, а отказ от повтора — потерять сообщение. Надёжность строится вокруг этого неопределённого состояния.

AiHummer отделяет создание ответа от его внешней доставки. Ответ ставится в durable outbox, воркер отправляет его в исходный канал, а состояние сохраняется. При временной ошибке работает настроенная политика повторов. Для побочных эффектов используется стабильный ключ ledger и барьер, который препятствует повторному выполнению уже зафиксированного действия.

Почему одной очереди мало

Очередь помогает не забыть работу после рестарта, но сама по себе обычно означает at-least-once: задача может выполниться больше одного раза. Воркер отправил сообщение, провайдер принял его, но подтверждение потерялось. Очередь видит таймаут и повторяет. Клиент получает два одинаковых ответа.

Поэтому каждому эффекту нужен идентификатор, стабильный при возобновлении. Он выводится из исходного запроса и операции, а не генерируется заново при каждой попытке. Перед выполнением барьер проверяет ledger: если эффект уже отмечен, повтор пропускается.

Что именно гарантирует stable key

В пределах одного ledger и одного стабильного ключа система может обеспечить выполнение не более одного раза. Это сильное свойство, но у него есть граница. Если внешняя система выполнила операцию, а локальная фиксация результата не состоялась, неопределённость остаётся. Идеальный путь — передавать тот же idempotency key внешнему API, чтобы он тоже дедуплицировал запросы.

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

Ограниченные повторы

Retry полезен для временных ошибок: сетевой сбой, rate limit, краткая недоступность. Он вреден для постоянных: неверный токен, запрещённый получатель, некорректный payload. Классифицируйте ошибки и задайте конечный бюджет попыток.

Backoff уменьшает нагрузку на сбойный сервис. Jitter не даёт сотням задач повториться одновременно. Учитывайте рекомендованное провайдером время, если оно возвращается. После исчерпания попыток задача должна получить явный финальный статус и быть видна оператору.

Фраза «повторяем до успеха» опасна без уточнения. Документация AiHummer говорит о повторе до успеха или исчерпания настроенной политики. Это не обещание доставки при заблокированном аккаунте, бесконечном outage или неверной конфигурации.

Восстановление после рестарта

Durable outbox хранит состояние вне памяти процесса. После запуска воркер подбирает незавершённые задания. Но восстановление нужно тестировать в разных точках: до фиксации задания, после фиксации до отправки, после отправки до подтверждения и после подтверждения до локальной отметки.

Для каждого теста измерьте число сообщений во внешнем канале, локальный статус, количество попыток и стабильность ключа. Хороший результат — не только «сообщение пришло», но и отсутствие дубля, понятная история и возможность продолжить обработку.

Наблюдаемость

Оператору нужны как минимум состояние задания, время следующей попытки, число attempts, последняя классифицированная ошибка и внешний идентификатор, если он получен. Отдельные метрики показывают возраст старейшей задачи, длину очереди, скорость успеха и число исчерпанных политик.

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

Идемпотентность бизнес-операций

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

Ключ должен переживать рестарт и повторный запуск того же хода, но отличать новую намеренную команду пользователя. Это проектируется на уровне домена. Слишком широкий ключ пропустит легитимное действие, слишком узкий создаст дубли.

Аварийный сценарий

Смоделируйте отключение сети на середине отправки. Не возвращайте клиенту уверенное «доставлено», пока нет подтверждения. Покажите промежуточный статус. После восстановления проверьте outbox и внешний канал. Если ответ неоднозначен, остановите автоматический retry и выполните read-only сверку.

Затем перезапустите gateway во время backoff. Убедитесь, что расписание попыток и stable key сохранились. После исчерпания бюджета проверьте, что задача не исчезла и оператор видит причину.

Чек-лист

  • Ответ фиксируется до внешней отправки.
  • Outbox хранится устойчиво.
  • Ошибки классифицируются на временные и постоянные.
  • Retry имеет лимит, backoff и jitter.
  • Stable key одинаков при восстановлении.
  • Внешний idempotency key используется, если доступен.
  • Неоднозначный результат сверяется до повтора.
  • Видны attempts, ошибка и внешний ID.
  • Исчерпанные задачи попадают в рабочую очередь оператора.
  • Рестарт тестируется в четырёх точках.
  • SLA не выводится из наличия ретраев.

Ручная сверка — штатный путь

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

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

Источники и ограничения

Официальные страницы: «Надёжная доставка и восстановление», «Мультиарендность и идемпотентность» и введение. Документация отдельно предупреждает: внешняя система должна поддерживать идемпотентность, если подтверждение может потеряться.

Ни outbox, ни retry не делают доставку безусловной при любых обстоятельствах. Они делают состояние наблюдаемым и восстановимым в заданных границах. Проверьте границы вашего канала до того, как обещать клиентам время и результат.

Yangi maqolalarga obuna

AiHummerʼning yangi maqolalarini elektron pochta orqali oling.

Izohlar

Izohlar yuklanmoqda…

Bepul start

AiHummerʼni sinab koʻring

AI-xodimlarni bulutda yoki oʻz uskunangizda ishga tushiring — Community tarifi bepul.