[bug][queue] {search-queue} растёт вечно: продюсеры есть, процессора не существует — 1902 мёртвых джоба в Redis (первая находка метрик #355) #379

Closed
opened 2026-07-05 23:18:08 +03:00 by agent_vscode · 0 comments
Collaborator

Суть

Алерт queue-growing (2026-07-05, первое реальное срабатывание метрик #355) указал на {search-queue}: wait=1902, active=0, failed=0 — и рост продолжается (вечером при приёмке было 1893). Проверка по Redis на island и по коду:

  • Продюсеры есть: page.listener.ts#L124-L167 кладёт PAGE_CREATED/UPDATED/DELETED/SOFT_DELETED/RESTORED на каждое изменение любой страницы; space.listener.ts#L27 и workspace.listener.ts#L27SPACE_DELETED/WORKSPACE_DELETED.
  • Консьюмера НЕ СУЩЕСТВУЕТ: в кодовой базе семь @Processor (history, notification, attachment, ai, email, general, file-task) — @Processor(QueueName.SEARCH_QUEUE) нет ни в одном файле и никогда не было (git log по всем веткам пуст).
  • Поиск при этом работает и от очереди не зависит: страницы индексируются DB-триггером tsvector (20240324T086800-pages-tsvector-trigger), attachments — своим путём; search.service по комментариям не ищет, констант SEARCH_INDEX_COMMENT* никто не использует.

Это апстримный код Docmost, чей консьюмер, по-видимому, живёт в EE-редакции (внешние search-драйверы). В нашем форке — чистый мёртвый груз: запись в Redis на каждое изменение страницы, бесконечный рост wait-листа, ложная «работа» для алертов.

Помечено в отчёте приёмки как «search=1893, разгребается» — как выяснилось, не разгребается: разбирать некому, active=0 всегда. Алерт queue-growing сработал корректно (к вопросу о его «переоценке» из #362 — чувствительность не трогать, он только что окупился).

Решение

  1. Убрать продюсеры: удалить инжект SEARCH_QUEUE и все searchQueue.add(...) из трёх листенеров (+ мёртвые константы SEARCH_INDEX_*, если не используются нигде больше). Если есть желание сохранить совместимость с апстримом для будущих мержей — обернуть в конфиг-флаг SEARCH_QUEUE_ENABLED=false по умолчанию, но проще удалить: diff с апстримом в этих файлах и так уже есть.
  2. Разовая очистка (ops, island, безопасно — джобы никогда не потреблялись, поиск от них не зависит):
docker exec gitmost-redis redis-cli --scan --pattern "bull:{search-queue}:*" \
  | xargs -r docker exec gitmost-redis redis-cli del
  1. Убедиться, что метрика bullmq_queue_depth{queue="search"} после этого стабильно 0 (метрика-сервис инжектит очередь — metrics-bull.service.ts#L49; при полном удалении очереди из кода поправить и там, при флаге — оставить).

Крайние случаи

  • Мерж апстрима в будущем вернёт эти строки — конфликт всплывёт явно, это приемлемо (или флаг из п.1).
  • PAGE_RESTORED/PAGE_SOFT_DELETED семантика: убедиться, что кроме search-очереди листенеры не делают на этих событиях ничего ещё (по коду — только enqueue; tsv-триггер отрабатывает на UPDATE строк сам).
  • Очистка Redis под нагрузкой: del листа на 1902 элемента — мгновенный, блокировки не будет.

Тесты / проверка

  • Существующие тесты листенеров — прогнать после удаления enqueue.
  • После деплоя + очистки: bullmq_queue_depth{queue="search"} == 0 сутки подряд, алерт молчит; редактирование страниц не приводит к росту.

Вне скоупа

  • Настоящий внешний поисковый бэкенд (typesense и т.п.) — если когда-нибудь понадобится, консьюмер будет писаться осознанно.
  • Пересмотр остальных очередей — не требуется, все остальные с живыми процессорами и нулевой глубиной (снято с прода).
# Суть Алерт `queue-growing` (2026-07-05, первое реальное срабатывание метрик #355) указал на `{search-queue}`: **wait=1902, active=0, failed=0** — и рост продолжается (вечером при приёмке было 1893). Проверка по Redis на island и по коду: - **Продюсеры есть**: [page.listener.ts#L124-L167](apps/server/src/database/listeners/page.listener.ts#L124-L167) кладёт `PAGE_CREATED/UPDATED/DELETED/SOFT_DELETED/RESTORED` на каждое изменение любой страницы; [space.listener.ts#L27](apps/server/src/database/listeners/space.listener.ts#L27) и [workspace.listener.ts#L27](apps/server/src/database/listeners/workspace.listener.ts#L27) — `SPACE_DELETED`/`WORKSPACE_DELETED`. - **Консьюмера НЕ СУЩЕСТВУЕТ**: в кодовой базе семь `@Processor` (history, notification, attachment, ai, email, general, file-task) — `@Processor(QueueName.SEARCH_QUEUE)` нет ни в одном файле и никогда не было (git log по всем веткам пуст). - **Поиск при этом работает и от очереди не зависит**: страницы индексируются DB-триггером tsvector (`20240324T086800-pages-tsvector-trigger`), attachments — своим путём; `search.service` по комментариям не ищет, констант `SEARCH_INDEX_COMMENT*` никто не использует. Это апстримный код Docmost, чей консьюмер, по-видимому, живёт в EE-редакции (внешние search-драйверы). В нашем форке — чистый мёртвый груз: запись в Redis на каждое изменение страницы, бесконечный рост `wait`-листа, ложная «работа» для алертов. Помечено в отчёте приёмки как «search=1893, разгребается» — как выяснилось, не разгребается: разбирать некому, active=0 всегда. Алерт queue-growing сработал **корректно** (к вопросу о его «переоценке» из #362 — чувствительность не трогать, он только что окупился). # Решение 1. **Убрать продюсеры**: удалить инжект `SEARCH_QUEUE` и все `searchQueue.add(...)` из трёх листенеров (+ мёртвые константы `SEARCH_INDEX_*`, если не используются нигде больше). Если есть желание сохранить совместимость с апстримом для будущих мержей — обернуть в конфиг-флаг `SEARCH_QUEUE_ENABLED=false` по умолчанию, но проще удалить: diff с апстримом в этих файлах и так уже есть. 2. **Разовая очистка** (ops, island, безопасно — джобы никогда не потреблялись, поиск от них не зависит): ```bash docker exec gitmost-redis redis-cli --scan --pattern "bull:{search-queue}:*" \ | xargs -r docker exec gitmost-redis redis-cli del ``` 3. Убедиться, что метрика `bullmq_queue_depth{queue="search"}` после этого стабильно 0 (метрика-сервис инжектит очередь — [metrics-bull.service.ts#L49](apps/server/src/integrations/metrics/metrics-bull.service.ts#L49); при полном удалении очереди из кода поправить и там, при флаге — оставить). # Крайние случаи - **Мерж апстрима в будущем** вернёт эти строки — конфликт всплывёт явно, это приемлемо (или флаг из п.1). - **`PAGE_RESTORED`/`PAGE_SOFT_DELETED` семантика**: убедиться, что кроме search-очереди листенеры не делают на этих событиях ничего ещё (по коду — только enqueue; tsv-триггер отрабатывает на UPDATE строк сам). - **Очистка Redis под нагрузкой**: `del` листа на 1902 элемента — мгновенный, блокировки не будет. # Тесты / проверка - Существующие тесты листенеров — прогнать после удаления enqueue. - После деплоя + очистки: `bullmq_queue_depth{queue="search"} == 0` сутки подряд, алерт молчит; редактирование страниц не приводит к росту. # Вне скоупа - Настоящий внешний поисковый бэкенд (typesense и т.п.) — если когда-нибудь понадобится, консьюмер будет писаться осознанно. - Пересмотр остальных очередей — не требуется, все остальные с живыми процессорами и нулевой глубиной (снято с прода).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#379