Строки листа 4.1 и 4.2, Этап 4 Task 1.
Беда, от которой сторожим: работник очереди умирает посреди отправки
(перезапуск сервера, обрыв связи). Снятие заморозки денег стоит ПОСЛЕДНИМ
шагом джоба отправки — до него он в этом случае не доходит. Итог на бою:
рассылка вечно «идёт», деньги клиента заморожены навсегда, в журнале тишина.
Команда client-sms:watch-stuck, каждые 15 минут. Движение меряется временем
последней записи в журнале рассылки: sent_count для этого не годится, он
проставляется только в самом конце. Порядок — решение владельца В-132:
сперва ОДНА попытка дожать (это безопасно, джоб пропускает уже отправленные
номера по ключу на номер), и только если и после неё не сдвинулась — срываем,
размораживаем остаток, ставим причину «сторож». Итог считаем из журнала.
Честно ждущая утра рассылка не трогается вовсе (строка 4.2): отличаем по
состоянию — ждущая waiting_window, зависшая sending. Ждущих дожимает
client-sms:resume-waiting.
Миграция 2026_08_01_100500 — две колонки: срок «зависла» в настройках
(правит владелец, строка 4.3) и отметка попытки дожать у рассылки. Прав не
требуют, наследуют привилегии таблиц; повторный накат переживают. Схема v9.17.
Проверено вырезанием, три выреза, все вернуты:
— убрал условие про состояние → покраснел тест 4.2, ждущую положили в очередь;
— убрал ветку «сперва дожать» → покраснел тест «кладётся в очередь ещё раз»;
— убрал пометку клиента → живой прогон под боевой ролью показал молчаливый сбой.
Живой прогон ПОД БОЕВОЙ РОЛЬЮ crm_app_user, парно:
с пометкой клиента — рассылка сорвана, заморозка 17.00 → 0.00;
без пометки — осталась «идёт», 17.00 зависли,
и в ОБОИХ случаях команда сказала «Сорвано: 1» и вернула успех.
Прогоны: ClientSms 249/249 (было 241, +8; 11 пачек, все с первой попытки),
приём лидов 17/17, phpstan ровно 2 чужие давние, pint чисто. Фронт не трогался.