Files
transcriber/tasks/items/stalled-pipeline-metric.md
T
av 75c6f0168a учёт: закрыт переезд хранилища, заведён урожай его ревью
- storage-without-pocketbase закрыта как реализованная: приёмка сошлась по всем
  пяти критериям записи и по двенадцати приёмочным свойствам рубрики ревью
  дизайна, работа лежит коммитом c9b7765
- урожай триажа ревью развёрнут в одиннадцать записей с тегом партии
  review-2026-08-23 и расставлен по зависимости, а не в конец списка
- находка про признак живости воркера слита в stalled-pipeline-metric: у неё та
  же причина — вставший конвейер неотличим от простоя
2026-08-23 08:41:49 +03:00

4.7 KiB

Показывать метрикой задачу, застрявшую в состоянии

  • Тип: feature
  • Категория: Очередь — Признак вставшего конвейера — вторая половина той же работы.
  • Зачем: Вставший конвейер неотличим от простоя: возраст задачи в состоянии не считается, и очередь без движения выглядит как отсутствие работы.
  • Теги: review-2026-08-23

По метрикам видно, что конвейер встал, и это отличимо от «работы нет».

Сегодня метрики считают события — принято, распознано, отказано, — а состояние очереди не считает ничто. Пустая очередь и очередь, где десять задач висят третий час, дают одинаковый нулевой прирост счётчиков.

Вторая половина той же слепоты — сам воркер. Ревью change 2026-08-23-storage-without-pocketbase (проход review-ops, O1) показало: живой воркер, которому не досталось работы, и воркер, чей шаг завис, дают одну и ту же картину — ни строки в журнале, ни движения счётчика. Признак живости здесь свой, отдельный от возраста задачи: очередь бывает пуста законно, а вот прогон цикла случается всегда.

Считать для этого NoopJobError нельзя — инвариант CLAUDE.md: значение «задач в этом состоянии нет» не логируется, не считается в метрику и не поднимает уровень. Нужен свой признак: отметка времени последнего прогона цикла у каждого воркера, а не счётчик пустых заходов.

Затрагивает

  • internal/metrics — метрика числа задач по состояниям, возраста самой старой из них и времени последнего прогона цикла у воркера;
  • цикл воркера internal/controller/worker — откуда снимается признак живости;
  • таблица задач: колонка состояния, по которой считаются числа, и отметка времени перехода, по которой считается возраст самой старой;
  • docs/architecture.md, раздел эксплуатации — что означает каждое число;
  • docs/database.md — частота съёма чисел.

Критерии приёмки

  • Число задач в каждом состоянии видно на /metrics. Оракул — тест: завести три задачи в разных состояниях и снять метрики.
  • Возраст самой старой задачи в состоянии виден числом и растёт, пока задача не сменила состояние. Оракул — тест на задаче с заведомо старой отметкой времени.
  • Съём чисел не мешает работе воркеров. Оракул — чтение кода: запрос идёт по индексу состояния и не берёт захват.
  • Живой воркер отличим от вставшего. Оракул — тест: у воркера, крутящего цикл на пустой очереди, отметка последнего прогона растёт; у воркера, чей шаг завис дольше периода опроса, стоит на месте.
  • NoopJobError не считается и не пишется. Оракул — тест с перехваченным журналом на пустой очереди: строк о задаче нет, счётчик отказов не вырос, а признак живости при этом двигается.

Рамки

Правило оповещения на этой метрике заводит задача owner-alerting — здесь только число. Порог «сколько считается застреванием» здесь не решается: он зависит от замеров speechkit-limits и intake-limits-measure.