Чому повторні вебхуки спричиняють дублікати повідомлень
Пояснюємо, як повторні спроби вебхуків створюють дублікати, як відрізнити retry від окремої події та де шукати причину.

Чому повторні спроби вебхуків спричиняють дублікати повідомлень?
Повторні спроби вебхуків корисні — аж поки ні. Один пропущений тайм-аут може перетворитися на два повідомлення, потім на три, і раптом те саме оновлення замовлення, скидання пароля чи сповіщення про доставку з’являється більше ніж один раз. Саме тоді питання «чому вебхуки дублюють повідомлення» перестає бути абстрактним і починає коштувати часу.
Перша помилка — вважати, що кожне повторене повідомлення означає збій у відправника. Іноді відправник повторив спробу саме так, як було задумано. Іноді ваш отримувач відповів занадто повільно. Іноді черга, воркер або повторне програвання журналу створили зайву копію після того, як вебхук уже надійшов один раз. Це різні проблеми, і для них потрібні різні виправлення.
Ці дублікати приходять через повторні спроби чи це окремі події вебхука?
Почніть із найпростішого тесту: порівняйте payload’и. Якщо два доставлення мають однаковий ID події, однаковий ID доставки або однакові метадані підпису, ймовірно, йдеться про одну подію, доставлену більше ніж один раз. Якщо бізнес-дані схожі, але ID різні, відправник міг створити дві реальні події, наприклад дві дії оформлення замовлення або два зміни статусу.
Не довіряйте лише часовій мітці. Дві доставки з інтервалом у 12 секунд усе ще можуть бути однією й тією ж подією, тоді як два повідомлення в одну секунду все ще можуть бути окремими подіями. Цикл повторних спроб і справжня подія, що дублюється, в поштовій скриньці можуть виглядати майже однаково, тому ID важливіші за людське око. Якщо ви не впевнені, як визначити повторну спробу вебхука, дивіться не на враження, а на ідентифікатори.
Є й практична підказка. Якщо ваша команда підтримки бачить дублікати email-сповіщень, а журнали вебхуків показують одну оригінальну подію та одну повторну спробу з тими самими метаданими доставки, проблема, ймовірно, у транспортуванні. Якщо в логах є дві окремі payload-записи з різними ID подій, дублікат з’явився вище за ланцюгом. Саме так і виглядають дублікати вебхуків що робити, коли потрібно швидко відрізнити транспортну проблему від справжнього дубля.
Яку саме поведінку повторних спроб використовує відправник?
Різні провайдери обробляють повторні спроби по-різному. Деякі автоматично повторюють після тайм-ауту. Деякі дозволяють оператору натиснути «повторити надсилання». Деякі повторно доставляють після тимчасового коду помилки. Дехто робить усе це одразу. Якщо ви не знаєте, який варіант активний, пошук причин дублікатів піде колами.
Ручне повторне надсилання зазвичай залишає людський слід: дію в панелі керування, примітку в тікеті або звернення в підтримку. Автоматичні повтори зазвичай мають шаблон, часто з дедалі більшими інтервалами між спробами. Політики повторної доставки на боці провайдера можуть бути менш помітними, бо відправник може трактувати мережеву помилку, проблему DNS або відповідь 5xx як привід спробувати ще раз без участі людини.
Попросіть у відправника письмову політику повторних спроб. Один провайдер може повторювати доставлення протягом 24 годин; інший — зупинятися після 3 спроб; ще інший — трактувати будь-яку відповідь не з діапазону 2xx як помилку. Це важливо, бо повідомлення, яке «дублюється» через 15 хвилин, може насправді бути 4-ю спробою того самого доставлення.
Що робить одне доставлення вебхука схожим на кілька повідомлень далі по ланцюгу?
З вебхуком може бути все гаразд. Дублювання може виникнути пізніше. Одна доставка може розгалужитися в чергу, потім у двох споживачів, далі в завдання з повторними спробами і врешті-решт у два вихідні сповіщення. Початковий вебхук був одним повідомленням; ваша система зробила так, ніби їх було кілька.
Таке особливо часто трапляється, коли обробник записує в чергу до того, як зафіксує запис у базі даних, або коли два воркери обидва забирають одне й те саме завдання після закінчення visibility timeout. Один вебхук перетворюється на кілька дій нижче по ланцюгу, бо внутрішній стан не був належно захищений. Здається, ніби відправник повторив спробу, але справжнє дублювання сталося всередині вашого стеку.
Подивіться, де вперше виникає побічний ефект. Лист був надісланий до вставки в базу? Рахунок був позначений як оплачений після старту завдання на сповіщення? Завдання було повторно поставлено в чергу, бо воркер упав у невдалий момент? Такі деталі важливіші за сам заголовок помилки.
Як ID payload’ів і метадані доставки можуть показати справжню причину?
ID у payload’і — ваш найкращий доказ. ID події, ID доставки, лічильник спроб, підпис запиту та часову мітку провайдера можуть показати, чи один вебхук було відтворено, чи було надіслано кілька окремих подій. Якщо відправник додає лічильник спроб, номер доставки або хеш запиту, збережіть це в логах і в базі даних.
За потреби зробіть невелику таблицю для порівняння. Для першого проходу достатньо трьох колонок: ідентифікатор payload’а, метадані доставки та бізнес-дія. Коли той самий ID події з’являється двічі, але ваша система відпрацювала лише один раз, повторна спроба може бути безпечною. Коли той самий ID події з’являється двічі, а ваша система спрацювала двічі, у вас є прогалина в дедуплікації.
| Поле | Що воно підказує | Типова ознака |
|---|---|---|
| ID події | Чи є вебхук тією самою подією | Той самий ID, повторна доставка |
| ID доставки | Яка транспортна спроба дійшла до вас | Різні ID доставки, та сама подія |
| Лічильник спроб | Скільки разів відправник пробував | Більше число після тайм-ауту |
| Підпис | Чи змінився body під час передачі | Невідповідність вказує на змінений payload |
Ознаки справжнього дубліката часто нудні — і це добре. Той самий payload, ті самі ID, та сама дія, повторна доставка. Ознаки окремих подій хаотичніші: близькі часові мітки, схожий вміст, але різні ID або різні джерельні записи. У цьому й полягає різниця між проблемою повторних спроб і проблемою продукту.
Чому повільні підтвердження часто запускають повторні доставки?
Більшість відправників вебхуків чекають на швидку відповідь 2xx. Якщо ваш сервер вагається 8 секунд, тайм-аут настає через 10 або повертає скидання з’єднання, відправник може не знати, чи було повідомлення оброблено. Тож він повторює спробу. З його точки зору, повторення безпечніше, ніж втрата події.
Ось чому доставка може успішно відбутися і все одно бути повторена. Мережа може відмовити після того, як ваша програма вже записала дані, або відповідь може затриматися рівно настільки, що відправник вирішить, ніби сталася помилка. Однієї пізньої відповіді достатньо. Відправник не має повної видимості у ваш внутрішній стан.
Навіть повільний запит до бази даних достатній, щоб запустити ланцюг. Так само як і «холодний» контейнер, заблокований потік або черга, яка чекає перед тим, як повернути успіх. Якщо endpoint вебхука робить щось важке до підтвердження отримання, дублікати повідомлень стають імовірнішими. Це проблема транспорту, а не вмісту.
Якщо вам потрібен пов’язаний патерн, стаття про події email-вебхуків для транзакційних листів розкриває ту саму ідею в обробці поштових подій, де таймінг і підтвердження визначають, що буде доставлено далі.
Що робити, якщо ваш отримувач обробив подію, але все одно повернув помилку?
Це неприємний випадок. Вебхук може створити замовлення, надіслати сповіщення або оновити запис клієнта, а потім кинути виняток під час формування відповіді. Відправник бачить помилку. Він повторює спробу. Тепер у вашої системи є два побічні ефекти від однієї події, а логи можуть не збігатися щодо того, який крок зламався першим.
Тому часткові збої потребують окремої уваги. Обробник, який зберіг повідомлення, а потім упав до повернення 2xx, можливо, уже виконав реальну роботу. Відправник, не знаючи про це, робить те, що йому наказано. Якщо ви питаєте, чому вебхуки дублюють повідомлення, це одна з найпоширеніших відповідей.
Перевіряйте код після побічного ефекту, а не лише перед ним. Чи записав обробник у базу даних, а потім упав на виклику метрик? Чи опублікував він у чергу, а потім перевищив тайм-аут під час форматування JSON? Чи надіслав вихідний лист, а потім згенерував помилку валідації? Невеликі збої можуть мати великі ефекти дублювання.
Як зупинити дублікати, спричинені повторними спробами, не втрачаючи події?
Практичне рішення — ідемпотентність. Зберігайте унікальний ключ для кожної події та відхиляйте повтори до того, як вони зможуть запустити другу дію. Цим ключем може бути ID події, delivery ID провайдера або комбінація джерела й хеша повідомлення. Важливо, щоб той самий вебхук відповідав тому самому збереженому результату.
Якщо можете, виконуйте перевірку на дедуплікацію і запис в одному атомарному кроці. Якщо перевірка відбувається першою, а вставка — пізніше, два воркери можуть змагатися і обидва вирішать, що вони перші. Унікальне обмеження в базі даних часто простіше за власні кеші в пам’яті, і воно переживає перезапуски. Тут мають значення дрібні дизайнерські рішення.
Використовуйте коротке вікно дедуплікації лише тоді, коли політика повторних спроб відправника коротка і добре відома. Якщо провайдер повторює спроби годинами, кеш на 5 хвилин — замало. Якщо подія може прийти через кілька днів, сховище дедуплікації має жити довше, ніж ваша пам’ять про інцидент.
Для команд, які працюють і з доставкою подій, і з комунікацією з клієнтами, посібник із налаштування автентифікації email стане корисним доповненням, бо тут діє той самий підхід: спочатку підтверди ідентичність, потім дій, і не довіряй одному сигналу окремо.
Надсилайте відповідь 2xx лише після того, як подія надійно збережена. Це не означає, що весь бізнес-процес має завершитися до підтвердження. Це означає, що отримувач має зберегти подію в надійному місці, а потім обробити її асинхронно. Так відправник бачить успіх лише один раз, а ваш воркер може безпечно повторювати спроби, не приймаючи ту саму подію повторно.
Коли слід підвищувати видимість повторних спроб вебхуків?
Логуйте повторні спроби з першого дня. Не чекайте на скаргу користувача. Простий рядок у логах з ID події, ID доставки, номером спроби, кодом відповіді та часом обробки може виявити шторм повторних спроб ще до того, як він розповзеться в листи, рахунки чи текстові повідомлення. Одне своєчасне сповіщення краще за десять тікетів підтримки пізніше.
Налаштуйте сповіщення, коли один і той самий ID події з’являється більше одного разу за коротке вікно або коли від одного джерела після релізу різко зростає кількість повторних спроб. Такий сплеск може означати тайм-аути, прострочені сертифікати, невдалий деплой або залежність нижче по ланцюгу, яка сповільнилася рівно настільки, щоб викликати повторні спроби. Чим швидше ви побачите шаблон, тим менше дублікатів доведеться розгрібати.
Тримайте в полі зору і отримувача, і відправника. Якщо панель провайдера показує 7 спроб, а ваші логи — лише 2, відсутні 5 можуть бути мережевими збоями. Якщо ваші логи показують 7 прийнятих подій для одного ID, проблема всередині вашого шляху дедуплікації. У будь-якому разі кількість підкаже, де шукати далі.
І якщо дублікати пов’язані з алертами або сповіщеннями, а не лише з вебхуками, та сама дисципліна застосовується і до повідомлень нижче по ланцюгу, особливо коли друга система реагує на першу, не перевіривши, чи перше повідомлення вже було оброблене.
На цій сторінці
← Усі статтіОдин клік. З нього ми розуміємо, про що писати далі.
Оцінок ще немає — ваша буде першою.
Коментарі
Коментарі читаємо перед публікацією.