Я заткнул надоедливого сторожа — и заодно заткнул агента, который отвечал покупателям
Раздражало настолько, что 21 сентября я решил закрыть вопрос одним движением: поставить кабинету паузу. В системе давно есть признак `business_profile.paused` — «этот аккаунт не в боевом режиме, не трогайте». Логично же: раз автозагрузка не оплачена и не нужна, пусть кабинет числится на паузе, сторож увидит паузу и замолчит.
Сторож замолчал. Через пятнадцать минут я полез в другую задачу и случайно заметил, что живой покупатель написал в чат кабинета — и агент ему не ответил. Вообще никак. Ни автоответа, ни уведомления оператору. Тишина.
Пауза оказалась значительно шире, чем я думал
Полез разбираться — и стало нехорошо. Признак `paused` читает не только сторож автозагрузки. Его читает общий резолвер ключей `_load_account_creds`, через который проходит буквально всё: и оператор, и ротация объявлений, и анализ диалогов, и — вот тут я споткнулся — чат-агент, который отвечает покупателям в реальном времени. Для резолвера пауза кабинета значит «нет доступа», он отдаёт `no_creds`, и вся цепочка ответа покупателю тихо обрывается ещё до генерации текста. Никакой ошибки, никакого алерта — просто агент не пишет.
У этого кабинета мессенджер-API бесплатный и рабочий, платной была только автозагрузка. То есть я выключил ЖИВУЮ функцию, чтобы заткнуть предупреждение о МЁРТВОЙ. Паузу снял в течение тех же пятнадцати минут, как увидел проблему — но за эти пятнадцать минут кабинет не отвечал ни одному покупателю, который мог написать.
Чинить решил не заглушкой «больше так не делать», а тем, что признак `paused` слишком грубый для задачи. Он должен значить «аккаунт целиком не в боевом режиме», а не «одна из подсистем не оплачена». Завёл отдельный узкий признак `business_profile.autoload_off` — он выключает ТОЛЬКО сторожа тишины автозагрузки и не касается резолвера ключей вообще. Сторож смотрит новый признак, агент как читал общий `paused`, так и читает — но кабинет больше не обязан притворяться выключенным целиком ради одной неоплаченной опции.
Пауза длиной в пятнадцать минут вскрыла вторую дыру
Самое неприятное я нашёл случайно, просто потому что пауза успела постоять эти пятнадцать минут. Есть ещё одна фоновая задача — почасовой сбор метрик по кабинету. Она НЕ фильтрует паузу аккаунта: берёт список активных кабинетов своим отдельным запросом и ставит задачу на каждый, включая тот, что на паузе. А дальше задача идёт за ключами доступа — и упирается в тот же резолвер `_load_account_creds`, который паузу как раз уважает и честно отдаёт «ключей нет». Итог: задача падает с `account_or_secret_not_found`. Каждый час. И каждое такое падение красит карточку в мониторинге.
То есть у меня внутри системы жили ДВА разных представления о том, какие кабинеты считать «активными» — одно в перечислителе метрик, другое в резолвере ключей, — и они расходились. Пока кабинет не бывал на паузе, расхождение молчало: оба списка совпадали. Пауза стала первым случаем, который его прощупал.
Правил так, чтобы это не повторилось молча: вынес оба запроса — из перечислителя метрик и из резолвера ключей — в именованные константы и написал тест, который сравнивает их результат на одних и тех же данных. Если кто-то в будущем поправит фильтр в одном месте и забудет про второе — тест покраснеет сразу, а не через месяц метрик с фантомными ошибками.
Открытый хвост, который я не стал прятать
Это чинит только пару «перечислитель метрик ↔ резолвер ключей». В системе ещё примерно четырнадцать похожих фоновых задач опрашивают список аккаунтов каждая своим запросом — ротация объявлений, дожим клиентов, вотчдог баланса, синк отзывов и так далее. Ни один я пока не проверил на то же расхождение вручную. То есть в теории пауза ЛЮБОГО кабинета по любой другой причине способна повторить ту же историю: где-то тихо перестанет работать нужная функция, а где-то начнутся часовые ложные тревоги.
Закрывать это можно двумя путями. Либо пройтись и поправить все четырнадцать мест по очереди — надёжно, но долго и по одному файлу за раз. Либо один раз переделать сам резолвер ключей так, чтобы он различал «ключей физически нет» и «кабинет специально поставлен на паузу» — рискованнее, потому что резолвер используется примерно в двадцати пяти местах, и часть из них — тот самый живой чат, а не фоновые задачи, которые можно спокойно откатить при ошибке.
Пока не выбрал. Но по крайней мере теперь знаю точно: если однажды кто-то из нас снова решит поставить кабинет на паузу ради тишины одного сторожа — стоит сначала спросить, что ещё в системе читает этот же флаг. Иногда это не тот вопрос, который приходит в голову за пятнадцать минут до того, как молчание заметит покупатель.