Практические разборы l3_builders
Webhook создаёт дубли: idempotency, retry и regression test
Практический выпуск CodeVibers: собираем FastAPI webhook, сохраняем idempotency key в SQLite, воспроизводим retry и блокируем конфликт payload.
Видео по теме
Практический выпуск CodeVibers: собираем FastAPI webhook, сохраняем idempotency key в SQLite, воспроизводим retry и блокируем конфликт payload.
Таймкоды
- 00:00 Две доставки — одна запись
- 00:45 Чистый проект
- 01:30 UNIQUE и payload hash
- 03:00 Retry и conflict 409
- 04:25 Regression tests
- 05:25 Browser proof
Shorts
- Два webhook — почему запись должна остаться одна
- Одна строка SQL останавливает дубли webhook
- Одинаковый ключ с другим payload нельзя считать retry
Источники выпуска
Исходники проекта из выпуска
Это тот же воспроизводимый проект, который собирается и тестируется в видео.
requirements.txt— Pinned runtime dependencies.app.py— Webhook endpoint, SQLite contract and result UI.demo.py— Real first/retry/conflict execution and report.tests/test_webhook.py— Positive, retry, conflict and missing-key regression tests.README.md— Reproducible run instructions.
Команды запуска и проверки
.venv/bin/python demo.py
.venv/bin/python -W ignore -m pytest -q
Практический материал из выпуска
Артефакт: Runnable FastAPI webhook service with SQLite idempotency storage and browser dashboard.
Что должно получиться: Project ZIP, endpoint code, schema, demo report and regression tests.
Видимый результат: Two identical deliveries produce one record; conflicting payload is blocked with HTTP 409.
Вход для демо: Repeated lead.created payload with X-Idempotency-Key evt_demo_42.
Выход демо: SQLite database, reports/demo.json, reports/result.html and four passing tests.
Проверка результата: Same event_id on retry, database count one, conflict 409, pytest green.
Как собрать
- create endpoint
- create UNIQUE table
- send first event
- repeat same event
- send conflicting payload
- open browser dashboard
Чеклист перед пилотом
- first created true
- retry created false
- one database row
- conflict 409
- four tests pass
Примеры команд, настроек или правил
CREATE TABLE ... idempotency_key UNIQUE
X-Idempotency-Key
payload hash
pytest -q
uvicorn app:app
Требования и рекомендации
Требования
- уникальный индекс
- стабильный key от источника
- атомарная запись
- 400 без ключа и 409 при конфликте
Рекомендации
- хранить ключ в durable storage
- связывать ключ с payload hash
- возвращать исходный event id на retry
- тестировать конфликт отдельно
Суть темы
Практический выпуск CodeVibers: собираем FastAPI webhook, сохраняем idempotency key в SQLite, воспроизводим retry и блокируем конфликт payload.
Что важно забрать
- Добавить уникальный idempotency key, payload hash и отрицательные тесты в собственный webhook.
- Рабочий webhook endpoint, SQLite contract, retry behavior and regression suite.
- Не совет о retries, а две реальные доставки, одна durable запись и конфликт payload на экране.
- Заменить blind retry на проверяемый exactly-once business effect.
Как применять на практике
Используйте материал как отправную точку: сформулируйте задачу, ограничьте область применения, выберите метрику качества и проверьте результат на небольшом сценарии до внедрения в production.
Практические шаги
- create endpoint
- create UNIQUE table
- send first event
- repeat same event
- send conflicting payload
- open browser dashboard
Рекомендации
- хранить ключ в durable storage
- связывать ключ с payload hash
- возвращать исходный event id на retry
- тестировать конфликт отдельно
Требования и ограничения
- уникальный индекс
- стабильный key от источника
- атомарная запись
- 400 без ключа и 409 при конфликте
Примеры
- две доставки evt_demo_42 создают одну запись
- тот же key с другой суммой получает 409
Антипримеры
- проверять дубли только в памяти процесса
Как проверить готовность
- database count equals one
- retry event_id equals first event_id
- conflict returns 409
- four tests pass
Навигация по выпуску
- 00:00 Две доставки — одна запись
- 00:45 Чистый проект
- 01:30 UNIQUE и payload hash
- 03:00 Retry и conflict 409
- 04:25 Regression tests
- 05:25 Browser proof