惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
O
OpenAI News
N
News and Events Feed by Topic
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Webroot Blog
Webroot Blog
Google Online Security Blog
Google Online Security Blog
云风的 BLOG
云风的 BLOG
N
News | PayPal Newsroom
H
Hacker News: Front Page
博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Last Watchdog
The Last Watchdog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Heimdal Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Schneier on Security
宝玉的分享
宝玉的分享
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Y
Y Combinator Blog
Cyberwarzone
Cyberwarzone
Microsoft Security Blog
Microsoft Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
GbyAI
GbyAI
Cloudbric
Cloudbric
TaoSecurity Blog
TaoSecurity Blog
人人都是产品经理
人人都是产品经理
P
Palo Alto Networks Blog
M
MIT News - Artificial intelligence
G
GRAHAM CLULEY
C
Check Point Blog
Apple Machine Learning Research
Apple Machine Learning Research
Last Week in AI
Last Week in AI
T
Troy Hunt's Blog
L
Lohrmann on Cybersecurity
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
量子位
博客园 - 聂微东
S
Securelist
博客园 - 三生石上(FineUI控件)
F
Full Disclosure
G
Google Developers Blog
L
LINUX DO - 热门话题
P
Proofpoint News Feed
AI
AI
PCI Perspectives
PCI Perspectives

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Все тесты зелёные, платежи зависли: 5 граблей интеграции без песочницы
Владимир Синявский · 2026-06-23 · via Все публикации подряд на Хабре

Осенью 2022-го мы добавляли в наш платёжный агрегатор новый способ оплаты: плательщик уходит по ссылке в приложение своего банка, подтверждает платёж там, а банк присылает нам нотификацию о результате. Песочница у банка была – формально. Отвечала статусами из позапрошлой версии протокола, а нотификации не присылала вообще; обещанные доработки ехали к нам дольше, чем наш дедлайн. Мы перестали ждать и написали двойника провайдера сами – по PDF со спекой, с тестом на каждый сценарий из документации. CI зелёный. Запускались осторожно, тремя волнами мерчантов: первые две прошли тихо. После третьей в саппорт пошли тикеты: у плательщика деньги списаны, у мерчанта платёж висит.

Сердиться на банк бессмысленно – у крупного провайдера тестовый стенд вечно живёт по остаточному принципу: прод приносит деньги, стенд – нет, и очередь доработок выстраивается соответственно. Для нас как интегратора это условие задачи. Документация на протокол в таких интеграциях – отдельный жанр: не публичная страница с актуальным API, а PDF-файл, который менеджер по интеграции присылает письмом. В нём попадаются поля и поведение, которых нет в открытом описании на сайте – фичи из-под полы, доступные тем, кому прислали нужную версию файла. Интереснее, что произошло с нашими тестами. Стаб исполняет ровно ту семантику, которую ты ему написал. Гоняя тесты против него, мы проверяли собственную фантазию о банке: внутренне непротиворечивую, прилежно покрытую и не обязанную совпадать с продом. Зелёный CI в такой схеме означает “наша фантазия согласована сама с собой” – и ничего больше.

Дальше – пять граблей, которые мы вытащили из этой интеграции. Все они про расхождение фантазии с реальностью, но в четырёх разных измерениях: время (грабли 1 и 2), завершённость (грабля 3), повторность и порядок (грабля 4), словарь (грабля 5).

Грабля 1. Нотификация обгоняет наш коммит

Первым в логах всплыло сообщение, которому мы сначала не поверили: обработчик нотификаций отвечал “платёж не найден” – по платежам, которые мы сами только что успешно создали.

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

// обработчик нотификаций, версия 1
public async Task<IResult> Handle(PaymentNotification n, CancellationToken ct)
{
    var payment = await payments.FindByProviderId(n.ProviderPaymentId, ct);
    if (payment is null)
        return Results.NotFound(); // здесь ломается: платёж есть, привязки ещё нет

    payment.ApplyStatus(MapStatus(n.Status));
    await payments.Save(payment, ct);
    return Results.Text("OK"); // почему именно "OK" – дойдём в грабле 5
}

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

Гонка целиком: нотификация успевает проскочить между ответом банка и коммитом привязки. В тесте такой порядок событий невозможен - его там пишет автор теста.

Гонка целиком: нотификация успевает проскочить между ответом банка и коммитом привязки. В тесте такой порядок событий невозможен - его там пишет автор теста.

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

Чинится это обороной в три рубежа. Первый: матчить нотификацию по своему ключу. OrderId существует с первой миллисекунды жизни платежа, и нотификация его несёт – банку мы сами его передали при создании. Второй: неузнанная нотификация – повод отложить, а не отказать; короткая очередь “сирот” с повторной обработкой через пару секунд снимает остаточные гонки. Отвечать банку ошибкой в расчёте на его ретраи тоже можно, но тогда ваша консистентность зависит от чужой retry-политики, пределы которой вы узнаете опытным путём. Наша первая версия, как видно из кода, жила именно так – 404 и надежда на повтор. Чаще всего банк действительно повторял, и со второй попытки всё сходилось; случаи, где повтор не доехал, копились в очереди зависших. Третий рубеж – полинг, и он заслуживает отдельной грабли.

Грабля 2. Нотификация имеет право не прийти

Гонки с недоехавшими повторами объясняли часть зависших платежей, но не все. У некоторых нотификация опаздывала на минуты, на часы – или не приходила совсем, ни первой попыткой, ни последующими. Сейчас я это пишу и сам слышу, как звучит: вебхуки доставляются по принципу “постараемся”, об этом сказано в любой статье про них. Мы тоже это знали. Отдельная ирония в том, что единственное, чего песочница банка не делала совсем – нотификации: как раз тот канал, который нас уронил. Но в стабе нотификация приходила всегда – мы сами так его написали, ведь в PDF сценария “нотификации не будет” нет. А чего нет в стабе, того нет и в тестах: наш CI честно проверял мир, в котором почта не теряется.

Майкл Найгард в “Release It!” называет точки интеграции главным источником нестабильности: каждая внешняя система однажды поведёт себя не так, как обещала документация. Зависшие после третьей волны платежи – наш взнос в эту статистику. Разгребали часа 3-4: поднимали статусы руками через запрос к банку, успокаивали мерчантов, а параллельно писали то, что должно было существовать с первого дня – страховочный полинг.

// страховка асинхронного канала: сами спрашиваем статусы незавершённых
public sealed class PendingPaymentsPoller(
    IPaymentStore payments, IProviderClient bank) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        while (!ct.IsCancellationRequested)
        {
            // дешёвая выборка по индексу: только платежи, у которых настал срок проверки
            var due = await payments.TakePendingDueForCheck(ct);
            foreach (var payment in due)
            {
                var status = await bank.GetPaymentStatus(payment.ProviderPaymentId, ct);
                payment.ApplyStatus(status);
                payment.ScheduleNextCheck(); // минута → пять → час → ... пока живёт платёж
                await payments.Save(payment, ct);
            }
            await Task.Delay(WakeInterval, ct);
        }
    }
}

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

Второй урок этой грабли – уже не про код. Дозированный запуск волнами нас не спас, хотя обязан был: зависший платёж снаружи неотличим от платежа, который просто ещё не оплатили, и без метрики “возраст самого старого незавершённого платежа” волны прошли вслепую. Канареечный запуск ловит только то, что вы измеряете.

Поллер закрыл дыру с потерянными нотификациями – и тут же подсветил платежи, с которыми всё было в порядке, кроме одного: завершаться они не собирались.

Грабля 3. Платёж, у которого нет финала

Разбирая очередь незавершённых, мы обнаружили, что заметная её часть вовсе не зависла. Плательщик создал платёж, получил ссылку – и не пошёл по ней. Передумал, отвлёкся, закрыл вкладку. Транзакция в промежуточном статусе, и никакого сбоя в этом нет: она будет жить так, пока ссылка не протухнет. В тестах подобного платежа не существовало. Стаб всегда доигрывал сценарий до конца, до успеха или до отказа – потому что тест без финала невозможно даже сформулировать. На чём ставить assert?

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

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

Стаб врал нам дважды. Сначала – что у каждой истории есть конец. Потом – что конец окончательный.

Грабля 4. Дубли приходят, порядок не гарантирован

Четвёртая грабля – классика жанра. Одна и та же нотификация приходила по два раза – иногда с интервалом в секунды, иногда в часы. А изредка нотификации приезжали не в том порядке, в котором банк менял статусы: сначала финальная, следом запоздавшая промежуточная. Стаб, разумеется, слал одну нотификацию на переход и строго по порядку – такая вежливость встроена в саму идею тестового сценария.

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

public void ApplyStatus(PaymentStatus incoming)
{
    if (incoming == Status)
        return; // дубль: вторая доставка – не ошибка, а вторник

    if (!StatusFlow.CanTransition(from: Status, to: incoming))
        return; // опоздавший промежуточный статус не перезатирает финальный

    Status = incoming;
    raisedEvents.Add(new PaymentStatusChanged(Id, incoming));
}

Идемпотентность плюс монотонность: повтор не делает ничего, переход возможен только вперёд по статусной машине. У монотонности одна оговорка, знакомая по грабле 3: недопустимый переход, который приносит деньги в уже закрытый платёж, нельзя глотать молча – он поднимает тот самый инцидент разбора. Игнорировать можно дубли; деньги – нет. Заводить всё это надо до того, как увидишь первый дубль, потому что первый дубль приезжает вместе с первым настоящим трафиком. Про идемпотентность с другой стороны баррикады – когда запросы шлёшь ты сам и дубли порождает твой собственный ретрай – я писал в посте про idempotency keys; там те же грабли, вид сбоку. Оставалась последняя – та, про которую обещал рассказать комментарий в самом первом примере кода.

Грабля 5. Контракт – это то, что приходит по сети

Последняя грабля выглядит мелочью, и в этом её коварство. На нотификацию нужно отвечать строкой “OK” в теле ответа. Буквальной строкой: не просто кодом 200, не пустым телом, не JSON’ом {"status":"ok"} – двумя байтами OK. Всё прочее банк считает недоставкой и присылает нотификацию снова. Наш стаб принимал любой успешный ответ – мы написали его по своему прочтению спеки, и наше прочтение оказалось щедрее банковского.

Форма ответа – полбеды, словарь подвёл сильнее. Однажды в нотификации пришёл статус, которого в нашем PDF не было. Потом – поле с токеном привязки счёта, о котором документация молчала: фича существовала, просто её описание до нас не доехало. Винить некого: PDF, который вам прислали, отстаёт от прода на неизвестную вам величину. Стаб наследует слепые пятна своего автора – он знает о протоколе столько же, сколько вы, и ни байтом больше. Тест против него не поймает расхождение между вашим прочтением и чужой реализацией: обе стороны такого теста писали вы.

Защита здесь скучная и надёжная. Парсинг словаря – толерантный:

private static PaymentStatus MapStatus(string wire) => wire switch
{
    "PENDING"   => PaymentStatus.Pending,
    "COMPLETED" => PaymentStatus.Completed,
    "REJECTED"  => PaymentStatus.Rejected,
    _ => PaymentStatus.Unknown // лог + алерт, но не exception
};

Неизвестный статус не роняет обработчик: платёж остаётся в промежуточном состоянии, дежурный получает алерт, а поллер из второй грабли дотащит транзакцию до правды, когда мы разберёмся, что это было. Рубежи работают вместе: толерантный парсинг безопасен лишь потому, что под ним страховка. И второе правило, которое я теперь завожу в первый день любой интеграции: сырые payload’ы – в лог, целиком. Когда придёт поле, которого нет в спеке, единственным источником истины окажется то, что реально пришло по сети.

Чеклист, который я унёс с собой

Если вам предстоит интеграция, а песочницы нет или про неё говорят “лучше без неё”:

  • Обработчик нотификаций – идемпотентный и монотонный с первого дня: дубли и беспорядок приедут с первым трафиком.

  • Нотификация – оптимизация. Гарантия – полинг.

  • Входящие события матчить по своему идентификатору, который существует с момента создания операции.

  • Неузнанное событие – отложить и повторить, не отказать.

  • Неизвестный статус – лог и алерт, не exception.

  • У вечных промежуточных состояний есть TTL; у закрытых по TTL – обработка посмертных событий.

  • Сырые payload’ы в лог с первого дня.

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

Чего в этом списке нет – призыва выбросить стабы. Против двойника можно и нужно гонять свою логику: статусную машину, идемпотентность, обработку ошибок. Просто это тесты вашей логики, а не их поведения, и зелёный цвет таких тестов ничего не говорит о проде. Контрактные тесты в духе Pact закрывают дыру честно, но требуют участия второй стороны: провайдер должен гонять ваши контракты у себя. Нашей второй стороной был PDF.

Самым информативным тестовым окружением в итоге оказался сам прод – с обороной в три рубежа, метрикой возраста и логом сырых событий он рассказал о протоколе больше, чем песочница и документация вместе. Хотелось бы узнавать такое до тикетов в саппорт, но для этого нужна песочница, которая ведёт себя как прод. Судя по моему опыту, в индустрии платежей это самый дефицитный артефакт.

Что почитать

  • Michael Nygard - “Release It!” (2nd ed., Pragmatic Bookshelf, 2018). Точки интеграции, таймауты, circuit breaker и почему внешняя система обязательно поведёт себя не по документации. Половина этого поста – частный случай его глав про integration points.

  • Vladimir Khorikov - “Unit Testing: Principles, Practices, and Patterns” (Manning, 2020). Управляемые и неуправляемые зависимости: какие можно подменять в тестах без вреда, а какие проверяются только настоящими. Банк тут – неуправляемая зависимость, очень показательная.

  • Stripe Docs - “Best practices for using webhooks”. Короткий трезвый список того, что провайдер нотификаций обещает, а чего не обещает. Лучше читать до интеграции, чем после.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

0%Стаб или моки по документации0

0%Запись и реплей реального трафика0

0%Сразу на проде, разбираем по логам0

0%У нашего провайдера нормальный стенд (повезло)0

Никто еще не голосовал. Воздержавшихся нет.