Постмортем инцидента для публикации
Превращает внутренний разбор аварии в публичный постмортем: хронология, настоящая причина вместо «человеческого фактора», выводы без самобичевания и без корпоративного тумана.
Пример запуска
Сгенерировано Claude Opus 5.5, 24 сентября 2026 г.
Значения переменных
- Описание инцидента
- 15 сентября в 08:58 по московскому времени была выкачена версия 2.14.0 бэкенда Ledgerly. В рамках деплоя обновлялся конфиг PgBouncer, и по ошибке в шаблоне значение max_client_conn откатилось с 500 до дефолтных 50. Из-за этого при обычном утреннем всплеске нагрузки (у нас пик входящих запросов приходится на 09:00–09:15 МСК, когда бухгалтеры открывают сервис в начале рабочего дня) пул соединений к базе оказался исчерпан. Начался массовый рост 502 и 504 на API-гейтвее. Был затронут в первую очередь эндпоинт создания счетов и генерации PDF, а также обработка вебхуков для интеграций с 1С и Контур.Диадоком. Сбой был замечен дежурным инженером по алерту на error rate в 09:04, после чего было принято решение откатить деплой. Дополнительно оказалось, что часть клиентских SDK при таймауте автоматически ретраили запрос на создание счёта, из-за чего у части пользователей задвоились записи — это пришлось разгребать руками после восстановления. Данные не потеряны, но по 180 счетам потребовалась ручная сверка и удаление дублей.
- Хронология
- 08:58 — выкачен релиз 2.14.0, конфиг PgBouncer заменён (max_client_conn 500→50, ошибка в шаблоне). 09:00 — начало обычного утреннего пика нагрузки. 09:02 — рост 5xx на API. 09:04 — сработал алерт по error rate, дежурный инженер взял инцидент в работу (это и есть момент обнаружения — 6 минут от начала проблемы). 09:09 — объявлен инцидент SEV1 в статус-канале, подключены бэкенд-разработчик и DBA. 09:14 — принято решение откатывать релиз, а не чинить конфиг на лету. 09:19 — начат роллбэк 2.14.0 через CI/CD. 09:31 — роллбэк завершён, конфиг PgBouncer восстановлен вручную. 09:36 — error rate и латентность вернулись к норме (22 минуты от обнаружения до устранения). 09:50 — инцидент закрыт как technically resolved. 09:50–13:00 — ручная сверка задвоенных счетов и разбор отставшей очереди вебхуков.
- Влияние на пользователей
- Около 14 000 из 22 000 активных аккаунтов получали 502/504 при создании счетов и генерации PDF в течение 38 минут (09:02–09:40). У 3 200 подписчиков вебхуков (интеграции с 1С и Контур.Диадоком) доставка событий задержалась до 40 минут, очередь полностью догналась только к 12:40. Из-за автоматических ретраев в клиентских SDK у 180 пользователей задвоились записи о счетах; данные не потеряны, но потребовалась ручная сверка и удаление дублей, что заняло у саппорта весь день 15 сентября.
- Действия по устранению
- 09:04 дежурный инженер подтвердил деградацию по дашборду error rate. 09:09 объявлен SEV1, подключены разработчик бэкенда и DBA. 09:14 решили откатывать релиз 2.14.0, а не чинить конфиг на лету. 09:19–09:31 выполнен роллбэк через CI/CD и вручную возвращено значение max_client_conn=500 в PgBouncer. 09:36 подтверждена нормализация error rate и латентности. До 13:00 саппорт вручную сверял задвоенные счета по логам и удалял дубли, клиентам с задвоением отправлены индивидуальные письма с извинениями.
- Принятые меры
- Уже сделано (к 18 сентября): в CI добавлена проверка diff конфигов PgBouncer, блокирующая деплой при отклонении от согласованных значений; на дашборд добавлен алерт на падение доли свободных соединений в пуле ниже 15%. В процессе: пишем ранбук по инцидентам с пулом соединений (готовность — 1 октября 2026). Запланировано: перевод конфигурации инфраструктурных сервисов (PgBouncer, Redis) на canary-раскатку с автооткатом по метрикам ошибок — срок 15 октября 2026; увеличение дефолтного размера пула с запасом x2 под пиковую нагрузку — срок 30 сентября 2026.
- Уровень открытости
- Публикуем на публичной странице статуса и в блоге компании для всех клиентов и партнёров. Можно называть технические детали, метрики и полный таймлайн, но без имён сотрудников, без упоминания конкретных клиентов с задвоенными счетами и без финансовых оценок ущерба.
Постмортем: ошибки при создании счетов и задержка вебхуков 15 сентября 2026 года
Опубликовано: [дата публикации]
Кратко
15 сентября с 09:02 до 09:40 МСК около 14 000 из 22 000 активных аккаунтов Ledgerly (примерно 64%) не могли создавать счета и генерировать PDF: API возвращал ошибки 502 и 504. Доставка вебхуков в интеграции с 1С и Контур.Диадоком задержалась, и очередь полностью разобралась только к 12:40.
Данные не потеряны. Из-за автоматических повторных запросов у 180 пользователей появились дубли счетов. Мы нашли и удалили их вручную, каждому из этих пользователей написали отдельно.
Причина: в 08:58 мы выкатили релиз 2.14.0. Он изменил конфигурацию PgBouncer, прокси между нашим приложением и базой данных PostgreSQL. В новом шаблоне конфигурации лимит клиентских соединений (max_client_conn) был равен 50 вместо прежних 500. Через две минуты начался ежедневный утренний пик нагрузки, лимита не хватило, и PgBouncer перестал принимать новые соединения.
Мы приносим извинения всем, у кого утро 15 сентября началось с ошибок, и особенно тем, кому пришлось разбираться с дублями.
Что увидели клиенты
| Что | Сколько клиентов | Когда | Последствия |
|---|---|---|---|
| Ошибки 502/504 при создании счетов и генерации PDF | ≈14 000 из 22 000 активных аккаунтов | 09:02–09:40 (38 минут) | Операции не выполнялись, их нужно было повторить |
| Задержка доставки вебхуков в 1С и Контур.Диадок | 3 200 подписчиков | С 09:02, очередь разобрана к 12:40 | События доставлены с опозданием, ни одно не потеряно |
| Дубли счетов | 180 пользователей | Возникли во время сбоя, удалены 15 сентября | Данные не потеряны, дубли удалены вручную, каждому пользователю мы написали |
Хронология
Всё время указано по Москве (UTC+3), 15 сентября 2026 года.
| Время | Событие | Причина или инициатор | Кто или что заметило |
|---|---|---|---|
| 08:58 | Мы выкатили релиз 2.14.0. Вместе с ним применился новый конфиг PgBouncer с max_client_conn = 50 вместо 500 |
Плановый деплой, ошибочное значение в шаблоне конфигурации | Никто: проверки значений конфигурации в пайплайне не было |
| 09:00 | Начался ежедневный пик нагрузки: бухгалтеры открывают сервис в начале рабочего дня | Обычная нагрузка | — |
| 09:02 | PgBouncer упёрся в лимит 50 соединений. API начал возвращать 502/504 | Исчерпан лимит клиентских соединений | Клиенты (ошибки в интерфейсе и интеграциях) |
| 09:02 → | Клиентские SDK начали автоматически повторять запросы на создание счёта после таймаута | Логика повторов в SDK | Никто до восстановления сервиса |
| 09:04 | Сработал алерт по доле ошибок. Дежурный инженер взял инцидент и подтвердил деградацию по дашборду | Мониторинг | Алерт по error rate |
| 09:09 | Дежурный объявил инцидент уровня SEV1 и подключил бэкенд-разработчика и администратора баз данных | Дежурный инженер | — |
| 09:14 | Мы решили откатить релиз целиком, а не исправлять конфиг на работающей системе | Команда инцидента | — |
| 09:19 | Мы запустили откат 2.14.0 через CI/CD | Команда инцидента | — |
| 09:31 | Откат завершился. Значение max_client_conn = 500 мы вернули в PgBouncer вручную |
Команда инцидента | — |
| 09:36 | Доля ошибок и время ответа API вернулись к обычным значениям | — | Мониторинг |
| 09:40 | Последние ошибки 502/504 у клиентов | — | Логи API-гейтвея |
| 09:50 | Мы закрыли техническую часть инцидента. Работа с последствиями продолжилась | Команда инцидента | — |
| 09:50–12:40 | Очередь вебхуков постепенно разбиралась | — | Мониторинг очереди |
| 09:50–[время] | Поддержка по логам нашла дубли счетов у 180 пользователей, удалила их и написала каждому пользователю | Команда поддержки | Анализ логов после восстановления |
Ключевые интервалы
- От изменения до обнаружения: 6 минут (08:58 → 09:04). От первых ошибок у клиентов до алерта прошло 2 минуты (09:02 → 09:04). Мы узнали о проблеме по симптому, то есть по ошибкам. Сигнала о её причине, заполнении пула соединений, у нас не было.
- От обнаружения до устранения: 32 минуты (09:04 → 09:36). Основное время ушло на три этапа: 10 минут до решения об откате (09:04 → 09:14), 5 минут до его запуска (09:14 → 09:19) и 12 минут на сам откат, включая ручное исправление конфига (09:19 → 09:31).
- Полное устранение последствий: вебхуки к 12:40, дубли счетов к [время].
Обнаружение в этом инциденте сработало быстро. Слабым местом оказались сроки реакции: путь от алерта к действию и продолжительность отката.
Почему это произошло
Симптом. API-гейтвей отдавал 502 и 504 на создание счетов, генерацию PDF и обработку вебхуков.
Почему? Запросы не получали соединения с базой: PgBouncer отказывал новым клиентам или держал их в ожидании дольше таймаута гейтвея.
Почему? Лимит клиентских соединений PgBouncer был 50. В обычный утренний пик нам нужно значительно больше, поэтому до этого релиза лимит составлял 500.
Почему лимит стал 50? Релиз 2.14.0 заменил конфигурацию PgBouncer, сгенерированную из шаблона. В шаблоне для max_client_conn стояло значение 50, а не 500. [Уточнить механизм: параметр пропал из шаблона и подставилось значение по умолчанию, в шаблоне была устаревшая версия или переменная не прокинулась в окружение.]
Почему ошибка дошла до продакшена?
- В пайплайне не было проверки, которая сравнивает параметры инфраструктурной конфигурации с согласованными значениями. Изменение, которое уменьшило лимит в 10 раз, прошло без предупреждения.
- Конфигурация PgBouncer применилась сразу на весь продакшен. Постепенной раскатки, на которой проблема проявилась бы на части трафика, не было.
- Релиз вышел в 08:58, за две минуты до ежедневного пика нагрузки. У нас не было правила, запрещающего выкатывать изменения инфраструктуры перед пиком.
Почему последствия оказались тяжелее простого простоя? 4. Эндпоинт создания счёта не защищён от повторов: он не принимает ключ идемпотентности и не распознаёт повторный запрос. Клиентские SDK после таймаута автоматически отправляли запрос ещё раз. Часть исходных запросов при этом успела выполниться на сервере, хотя клиент получил таймаут. Так появились дубли. [Проверить, что механизм именно такой.] 5. Откат релиза через CI/CD не вернул прежнюю конфигурацию PgBouncer, и её пришлось исправлять вручную. [Проверить.] Это удлинило восстановление.
Ни на одном из этих шагов ответ не сводится к тому, что «кто-то ошибся». Ошибка в шаблоне возможна всегда. Проблема была в том, что между ошибкой и продакшеном не стояло ни одной проверки, а сам сервис не был готов к повторным запросам.
Что мы изменили и изменим
Уже сделано (к 18 сентября)
- Проверка конфигурации в CI. Пайплайн сравнивает конфигурацию PgBouncer с согласованными значениями и блокирует деплой, если они расходятся.
- Алерт на заполнение пула. Мы получим сигнал, когда доля свободных соединений упадёт ниже 15%, то есть до того, как клиенты начнут видеть ошибки.
В работе
- Инструкция для дежурных по инцидентам с пулом соединений. В ней будут признаки, порядок диагностики и критерии выбора между откатом и исправлением на месте. Срок: 1 октября 2026 года.
Запланировано
- Запас по размеру пула. Поднимем лимит соединений с двукратным запасом относительно пиковой нагрузки. Срок: 30 сентября 2026 года.
- Постепенная раскатка инфраструктурных конфигураций. PgBouncer и Redis будем обновлять сначала на части трафика, с автоматическим откатом при росте ошибок. Срок: 15 октября 2026 года.
Если вас это затронуло
- Если вы создавали счёт между 09:02 и 09:40 и получили ошибку, проверьте, что счёт существует. Если его нет, создайте заново.
- Если в вашем аккаунте были дубли, мы написали вам отдельно, и лишние записи уже удалены.
- Если вы видите расхождения в данных 1С или Диадока за 15 сентября, напишите в поддержку: [контакт].
Замечания редактора
Список замен
| Было | Стало | Зачем |
|---|---|---|
| «была выкачена версия 2.14.0» | «мы выкатили релиз 2.14.0» | Появился субъект |
| «по ошибке в шаблоне значение откатилось» | «в новом шаблоне конфигурации лимит был равен 50» | «Откатилось» звучит так, будто значение изменилось само. На деле его изменил наш релиз |
| «пул соединений к базе оказался исчерпан» | «PgBouncer упёрся в лимит 50 соединений и перестал принимать новые» | Конкретный механизм вместо «оказался» |
| «начался массовый рост 502 и 504» | «API начал возвращать 502/504» | Ясно, кто возвращал ошибки |
| «был затронут эндпоинт…» | «клиенты не могли создавать счета и генерировать PDF» | Описано, что видел пользователь |
| «сбой был замечен дежурным инженером по алерту» | «сработал алерт, дежурный инженер взял инцидент» | Разделены два события: алерт и реакция человека |
| «было принято решение откатить деплой» | «мы решили откатить релиз целиком» | Субъект, плюс сохранена альтернатива, которую отвергли |
| «подключены бэкенд-разработчик и DBA» | «дежурный подключил…» | Субъект |
| «часть клиентских SDK ретраили» | «SDK автоматически повторяли запросы» + причина в разделе «Почему» | Ответственность не перекладывается на клиентов (см. ниже) |
| «задвоились записи» | «появились дубли счетов» | Нейтрально и понятно без жаргона |
| «пришлось разгребать руками» | «поддержка по логам нашла и удалила дубли» | Конкретное действие |
| «инцидент закрыт как technically resolved» | «закрыли техническую часть, работа с последствиями продолжилась» | Без жаргона. Честно сказано, что для клиентов инцидент на этом не закончился |
| «выполнен роллбэк» / «подтверждена нормализация» | «мы запустили откат» / «вернулись к обычным значениям» | Субъект |
| «клиентам отправлены письма» | «мы написали каждому пользователю» | Субъект |
| «в CI добавлена проверка» | «пайплайн сравнивает… и блокирует деплой» | Описано, что именно делает мера |
Что смягчил и почему
- Слово «ошибка» применительно к шаблону. Я не писал, кто или что её внёс, и перенёс акцент на отсутствие проверок. Это не прячет суть: сам факт ошибки в шаблоне назван прямо.
- SDK. Если это ваши SDK (судя по контексту, да), формулировка «часть клиентских SDK» читается как «виноваты клиенты». Я перенёс ответственность на сервер без идемпотентности. Если SDK сторонние, формулировку нужно поменять, но корневая причина остаётся той же.
- Извинение оставил коротким и без самобичевания. Обороты вроде «к счастью, данные не пострадали» я не использовал: отсутствие потерь указано как факт.
Расхождения в исходных данных (исправить до публикации)
- «22 минуты от обнаружения до устранения» не сходятся с таймлайном. С 09:04 до 09:36 прошло 32 минуты. Число 22 получается от решения об откате (09:14) до 09:36. В тексте стоит 32. Публичный читатель пересчитает сам.
- «6 минут от начала проблемы» считаются от деплоя, а клиенты видели ошибки с 09:02, то есть алерт сработал через 2 минуты. Я привёл оба интервала. Здесь цифры в вашу пользу, и их стоит показать.
- Ошибки нормализовались в 09:36, а влияние на клиентов указано до 09:40. Объясните эти 4 минуты (кэш, повторы, долгие запросы) или выровняйте время.
- Вебхуки. В исходнике сказано «задержка до 40 минут» и одновременно «очередь догналась к 12:40». Это 3,5 часа. Одно из двух неверно. Возможно, 40 минут составляла задержка для большинства, а хвост разбирался дольше. Тогда так и напишите.
- Дубли. В одном месте сверка шла «до 13:00», в другом заняла у поддержки «весь день». Нужно одно время окончания, в тексте стоит плейсхолдер.
Где не хватает данных
- Почему в шаблоне оказалось 50. Это самое важное недостающее звено. Сейчас разбор останавливается на «ошибке в шаблоне». Кстати, у самого PgBouncer значение
max_client_connпо умолчанию равно 100, а не 50, так что «дефолт 50», скорее всего, ваш собственный. Выясните, откуда он взялся. - Доля ошибочных запросов. «14 000 аккаунтов получали ошибки» не говорит, падал ли каждый запрос или каждый пятый. Одна цифра («до N% запросов на создание счёта завершались ошибкой») сделает раздел о влиянии заметно сильнее.
- Не отправлены ли дубли контрагентам. Если повторный счёт успел уйти через вебхук в Диадок или 1С, удаления у вас недостаточно: документ уже у контрагента. Проверьте это первым делом. Если такие случаи были, о них нужно написать прямо и в начале.
- Обновлялась ли публичная статус-страница во время инцидента и когда. SEV1 объявили в 09:09 во «внутреннем статус-канале». Клиенты спросят, когда об инциденте узнали они.
Пробелы в мерах, которые заметят
- Нет меры против дублей. Это главная дыра. Вы описали, как дубли появились, но ничего не обещаете, чтобы это не повторилось. Любой технический читатель спросит про ключ идемпотентности на создании счёта и про политику повторов в SDK. Без срока не публикуйте, но решите этот вопрос до выхода текста: пусть в разделе будет хотя бы «ключ идемпотентности для создания счетов, срок такой-то».
- Нет меры про время деплоя. Релиз вышел за 2 минуты до пика. Правило вроде «никаких изменений инфраструктуры с 08:30 до 10:00» стоит почти ничего, а без него раздел «Почему» выглядит незавершённым.
- Откат не вернул конфиг (если это так). Мера про постепенную раскатку это частично закрывает, но стоит отдельно сказать, что откат релиза теперь возвращает и инфраструктурную конфигурацию.
- «Пул с запасом x2». Уточните, какой параметр вы меняете:
max_client_connилиdefault_pool_size. Это разные вещи, и увеличение второго упирается вmax_connectionsPostgreSQL. Сейчас мера сформулирована расплывчато.
Проверка на лишнее
- Имён сотрудников нет, только роли: дежурный инженер, администратор баз данных, поддержка.
- Конкретных клиентов нет. 180 названо числом.
- Финансовых оценок нет.
- Подрядчиков нет, 1С и Контур упомянуты только как направления интеграций, без претензий к ним.
- Внутренних адресов, хостов и идентификаторов нет. Имя параметра
max_client_connоставил: это публичная настройка PgBouncer, а не ваш идентификатор. - Перед публикацией уберите маркеры [уточнить] и [проверить] и заполните плейсхолдеры: дату публикации, время окончания работы с дублями, контакт поддержки.
Похожие промпты
Структура технической статьи для Хабра
Собирает план технической статьи под аудиторию Хабра: заход, который не выглядит рекламой, честная структура разбора и места, где нужны детали, а не общие слова.
Разбор дискуссии в треде: аргументы сторон
Разбирает длинный спор в X: кто что утверждает, какие аргументы опираются на факты, где стороны спорят о разном и в чём они на самом деле согласны.
Анализ трендов в X по теме
Разбирает, что обсуждают в X по вашей теме прямо сейчас: сюжеты, тональность, кто задаёт тон, где органика, а где накрутка.
Вирусные посты для Telegram-канала
Пишет посты для Telegram-канала с высоким потенциалом пересылок: цепляющие первые строки, проверенные виральные форматы и призывы, которые запускают репосты.