Слогер Создать блог
Разработка

Как поймать потерю сообщений в outbox: kill-хук, состояние in-flight и идемпотентный ключ

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

Строка outbox помечена как отправленная, а брокер о сообщении ничего не знает. Процесс умер ровно между двумя действиями — записью статуса и публикацией. Окно открыто в каждом тике, просто в обычном прогоне его никто не задевает.

Суть бага в порядке операций. Воркер сначала меняет статус строки на sent и только потом вызывает publish. Пока вызов возвращается нормально, всё сходится. Как только между двумя строками вклинивается сбой — падение, OOM, рестарт пода, — строка остаётся sent навсегда, а сообщение не уходит. Следующий запуск её пропустит: фильтр смотрит только на pending. Пользователь не получит ничего, в логах будет чисто.

Поэтому happy-path не доказывает ничего. Тест, который просто прогоняет воркер и печатает результат, показывает зелёный сценарий и молчит о потерянных строках. Дыру видно только тогда, когда падение воспроизводится намеренно.

Что нельзя смешивать

Задача держится на разнице между тремя вещами, и слабые решения рушатся именно здесь.

  • Порядок записи внутри одного процесса. Тут всё детерминировано: сначала статус, потом публикация. Кандидат должен показать, что понимает этот порядок, а не угадывает его.
  • Что увидит следующий запуск. Строка лежит в sent и никем не подхватится.
  • Что вообще способен доказать двойник в памяти. Он не говорит о реальной долговечности ровно ничего: ни про диск, ни про то, как поведут себя два хоста, если один из них потеряет связь с другим. Двойник показывает только порядок событий внутри процесса — и выдавать его за гарантию сохранности нельзя.

Смешение этих слоёв и рождает фразу «у меня же всё работало». Работало — до момента, когда между записью статуса и вызовом publish появилась задержка.

Что требуется в задании

Кандидат получает buggy_worker.py и брокера-двойника в памяти. Задача — сделать баг наблюдаемым и предложить состояние, из которого система продолжит работу после краха.

Добавь kill-хук, который останавливает процесс после записи статуса. Покажи, что строка sent, а список сообщений брокера пуст. Предложи стейт-машину, которая переживёт такой крах. Публикация должна быть идемпотентной по id строки. Никакого реального сетевого брокера. Чистый прогон без kill-хука проходным не считается. Таймбокс — 90 минут.

Формулировка узкая намеренно. Оценивают одну стейт-машину, а не платформенный рефакторинг: ранний коммит, путь возобновления и ключ идемпотентности. 90 минут — это ограничение найма, а не оценка того, сколько времени займёт аккуратная правка в продакшене.

Как выглядит рабочая связка

Хук делают не через настоящий сигнал, а через исключение внутри процесса — так тест остаётся юнит-тестом и запускается одной командой на любой машине с Python. Порядок в тике получается такой: строка переводится в sent, счётчик попыток растёт, срабатывает хук и выбрасывает SystemExit. До публикации дело не доходит.

Ожидаемая диагностика незамысловатая: текст выхода, слово sent и пустой список сообщений. Видите ровно это — окно найдено. Запуск в два шага: сначала pytest по файлу с тестом, потом короткий прогон, который печатает состояние. Тестам не нужны ни приватные токены, ни хостовая консоль, ни конкретный вендор модели.

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

Таблица проверок

ПроверкаПроходПровал
Kill-хук после записи статусаСтрока sent, список брокера пустПрогнан только happy path
Состояние для возобновленияСтатус in-flight отличим от sentОбработчик исключения оставляет sent
Второй тикОдно сообщение, затем sentВторой тик пропускает строку навсегда
Идемпотентный ключПовтор не добавляет второе телоДубликат публикации переименован и оставлен рядом
Границы правкиПатч живёт внутри воркера и тестаПоявляется новый продукт очереди или облачный аккаунт
Записка с доказательствомСказано, чего двойник доказать не можетЗаявлена долговечность на диске или fencing между хостами

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

Типичные провалы

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

Где подход не работает

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

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

На выходе у упражнения ровно три артефакта: воспроизводимый падающий тест, отдельное состояние in-flight между pending и sent и ключ идемпотентности по id строки. Всё, что выходит за эти рамки, — расползание объёма, за которое в таймбоксе 90 минут никто спасибо не скажет.

По материалам: career. Текст переработан редакцией Слогера.

← На главную

Рекламное место — Конец поста
Реклама · Слогер

Комментарии (0)

Войдите, чтобы комментировать.

Пока нет комментариев. Будьте первым.

Fluxs lenta
Реклама · fluxs.ru
Разработка

Как внедрять ИИ в компании: разбор четырёх подходов и метрик, которые ничего не показывают

Меморандум «мы теперь AI-first» — заявление о намерениях. Что реально произойдёт с командой, решает то, что компания поставила под него: готовность, галочка или расход токенов.

Слогер 10.10.2026 ▲ 0
Карьера

Как читать WARN-уведомления о сокращениях: разбор данных по Массачусетсу за 2026 год

Уведомления WARN — самый надёжный публичный сигнал о массовых увольнениях в США. Показываю на примере Массачусетса, как вытащить из них смысл, где цифры врут и что делать, если вы попали в список.

Слогер 10.10.2026 ▲ 0
Карьера

Разбор: ИИ-агент, который читает каждую вакансию до отклика

Массовые отклики ботом дают одно собеседование на 250 заявок. Агент, который сначала читает объявление целиком, — на 32. Разбираем, как он устроен и что из этого применимо без всяких подписок.

Слогер 10.10.2026 ▲ 0
Личный опыт

Как общаются в известной многодетной семье во Владикавказе

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

Алла Надежкина 09.10.2026 ▲ 0
Маркетинг

250 тысяч за настройку, ещё до первого звонка. Что мы сделали вместо этого

Мы изучили, сколько стоит голосовой робот для обзвона. Только за настройку, до первого звонка и без оплаты разговоров, у специализированных поставщиков просят порядка 250 тысяч рублей. У нас этот модуль встроен в платформу: заявка превращается в лид, робот звонит, результат записывается в карточку, менеджер получает задачу. Готовый шаблон сценария, подключил, поправил тексты и звонишь. Рассказали, как это устроено и почему подход «готовое решение» дешевле: https://fluxs.ru/golosovoy-robot-dlya-obzvona?utm_source=telegram&utm_medium=social&utm_campaign=voice-calls

Слогер 09.10.2026 ▲ 1
Fluxs lenta
Реклама · fluxs.ru
Карьера

Как ИИ-пайплайн превращает 1500 вакансий в 12 откликов: разбор пяти стадий поиска работы

Автор прогнал через систему больше 1500 объявлений и оставил в очереди двенадцать. Разбираем, как устроены стадии, где правила работают лучше модели и почему последнюю милю нельзя автоматизировать.

Слогер 09.10.2026 ▲ 0
Fluxs lenta
Реклама · fluxs.ru