Files
bare/docs/decisions/073-push-failure-reason-in-log.md
T
mayatnikovandClaude Opus 5 f9ac83bef8 Развести номера ADR: 064/065/066 этой ветки → 073/074/075
Ветка отведена от 522ba89, где последним был ADR-063, и заняла
064–072. Тем временем в main через #3 и #4 пришли свои 064
(строка ввода — div вместо form), 065 (стороны сообщений)
и 066 (серверного перца нет).

Переезжают три ADR этой ветки, 067–072 остаются на месте:
их номера свободны, а внутренние ссылки менять незачем.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QR8uS3zGkybzWRW4GEY1oz
2026-08-24 11:23:12 +03:00

3.5 KiB

ADR-073: Код причины отказа push-сервиса в журнале

Уточняет ADR-047.

Контекст

ADR-047 убрал из журнала адрес подписки: отказ отправки пишется классом, текст ошибки транспорта не печатается вовсе. Под то же правило попал и ответ push-сервиса — в журнал уходил один статус: пуш: push-сервис ответил 403.

Цена выяснилась на работающем сервере. APNs отвечал 403 на каждый пуш, потому что в VAPID-токен уезжал sub = "mailto:mailto:admin@xmatic.team": webpush-go приписывает mailto: всему, что не начинается с https:, а в окружении субъект записан правильным URI. Сутки не уходило ни одного пуша, и по журналу это выглядело как «что-то с пушами»: просроченный ключ, чужой субъект, лимит вендора и мёртвая подписка дают один и тот же 403. Причина лежала в теле ответа: {"reason":"BadJwtToken"}.

Код причины от push-сервиса — диагностика вендора, а не данные пользователя. Но тело ответа приходит снаружи, и класть его в журнал целиком нельзя: в нём может оказаться адрес подписки.

Решение

  • В журнал уходит статус и, если он разобран, короткий код причины: пуш: push-сервис ответил 403 (BadJwtToken).
  • Читается не больше 200 байт тела; остаток дочитывается ради переиспользования соединения. Код берётся из полей JSON reason, error, message — в этом порядке — либо из тела целиком, если оно само короткая строка.
  • В журнал идёт только первая строка не длиннее 64 символов из латиницы, цифр, _, - и пробелов. Точка, :, / и @ встречаются в адресах подписки и именах хостов, поэтому строка с ними отбрасывается целиком и остаётся один статус.
  • Правило ADR-047 про транспорт не меняется: ошибка соединения по-прежнему сводится к классу, её текст не печатается, адреса подписки в журнале нет.

Следствия

  • Отказ push-сервиса читается по журналу и чинится по нему же.
  • Часть вендорских кодов не разберётся: FCM отвечает вложенным объектом, а коды с точкой в имени не проходят алфавит. Тогда в журнале остаётся статус, как раньше. Осознанно: молчание безопаснее догадок о чужом теле.
  • Ответы 404 и 410 пишутся не строкой, а снятием подписки — так было и остаётся (ADR-011).