fix(queue): убрать мёртвую очередь {search-queue} (#379) #380

Merged
vvzvlad merged 1 commits from fix/379-remove-dead-search-queue into develop 2026-07-05 23:44:58 +03:00
Collaborator

Summary

Убираю мёртвую очередь {search-queue}: продюсеры есть, консьюмера нет и не было (он живёт в EE-редакции Docmost). Поиск работает через DB tsvector-триггер и от очереди не зависит — очередь просто копила джобы (1902 залипших в Redis, первое реальное срабатывание алерта queue-growing из #355, сработал корректно). closes #379.

Что убрано

  • Продюсеры (3 листенера): @InjectQueue(SEARCH_QUEUE) + все searchQueue.add(...) + гейт isTypesense() (он оборачивал только search-энкью). page.listener.handlePageUpdated делал ТОЛЬКО search-энкью → удалён вместе с @OnEvent(PAGE_UPDATED); остальные хендлеры сохранили aiQueue.add.
  • Регистрация очереди (queue.module.ts) и инжект в метрики + запись {label:'search'} (metrics-bull.service.ts).
  • Константы: QueueName.SEARCH_QUEUE + 6 неиспользуемых SEARCH_INDEX_* (grep-подтверждено). Общие QueueJob (PAGE_*, SPACE_DELETED, WORKSPACE_DELETED — их юзают AI-очередь / embedding/history/notification процессоры) сохранены.

Поиск (tsvector-триггер, search.service) и WS-слушатель PAGE_UPDATED не тронуты.

How verified

apps/server tsc --noEmit0 ошибок; jest metrics embedding history.processor page-ws.listener6 suites / 52 tests passed. Висячих ссылок на удалённые символы по всему репо нет. Внутреннее ревью — APPROVE (потерь не-поисковых сайд-эффектов нет; PAGE_UPDATED-событие сохраняет живого WS-консьюмера).

Ops (за оператором, вне scope кода)

  1. Разовая очистка Redis (безопасно — джобы никогда не потреблялись):
    redis-cli --scan --pattern "bull:{search-queue}:*" | xargs -r redis-cli del
  2. После деплоя убедиться, что bullmq_queue_depth{queue="search"} стабильно 0 (метрика больше не инжектит эту очередь).

Вне scope

Другие мёртвые EE-константы (SEARCH_REMOVE_*/TYPESENSE_FLUSH) оставил — их удаление не в scope #379.

Checklist

  • критерии приёмки из #379 (убраны продюсеры + вся SEARCH_QUEUE-обвязка)
  • поиск не сломан (tsvector-триггер не тронут); DI грузится; тесты зелёные
  • вне scope ничего не менялось (6 файлов)
## Summary Убираю мёртвую очередь `{search-queue}`: продюсеры есть, консьюмера нет и не было (он живёт в EE-редакции Docmost). Поиск работает через DB tsvector-триггер и от очереди не зависит — очередь просто копила джобы (1902 залипших в Redis, первое реальное срабатывание алерта `queue-growing` из #355, сработал корректно). closes #379. ## Что убрано - **Продюсеры (3 листенера)**: `@InjectQueue(SEARCH_QUEUE)` + все `searchQueue.add(...)` + гейт `isTypesense()` (он оборачивал только search-энкью). `page.listener.handlePageUpdated` делал ТОЛЬКО search-энкью → удалён вместе с `@OnEvent(PAGE_UPDATED)`; остальные хендлеры сохранили `aiQueue.add`. - **Регистрация** очереди (`queue.module.ts`) и **инжект в метрики** + запись `{label:'search'}` (`metrics-bull.service.ts`). - **Константы**: `QueueName.SEARCH_QUEUE` + 6 неиспользуемых `SEARCH_INDEX_*` (grep-подтверждено). Общие `QueueJob` (`PAGE_*`, `SPACE_DELETED`, `WORKSPACE_DELETED` — их юзают AI-очередь / embedding/history/notification процессоры) сохранены. Поиск (tsvector-триггер, `search.service`) и WS-слушатель `PAGE_UPDATED` не тронуты. ## How verified `apps/server` `tsc --noEmit` → **0 ошибок**; `jest metrics embedding history.processor page-ws.listener` → **6 suites / 52 tests passed**. Висячих ссылок на удалённые символы по всему репо нет. Внутреннее ревью — APPROVE (потерь не-поисковых сайд-эффектов нет; `PAGE_UPDATED`-событие сохраняет живого WS-консьюмера). ## Ops (за оператором, вне scope кода) 1. Разовая очистка Redis (безопасно — джобы никогда не потреблялись): `redis-cli --scan --pattern "bull:{search-queue}:*" | xargs -r redis-cli del` 2. После деплоя убедиться, что `bullmq_queue_depth{queue="search"}` стабильно 0 (метрика больше не инжектит эту очередь). ## Вне scope Другие мёртвые EE-константы (`SEARCH_REMOVE_*`/`TYPESENSE_FLUSH`) оставил — их удаление не в scope #379. ## Checklist - [x] критерии приёмки из #379 (убраны продюсеры + вся SEARCH_QUEUE-обвязка) - [x] поиск не сломан (tsvector-триггер не тронут); DI грузится; тесты зелёные - [x] вне scope ничего не менялось (6 файлов)
agent_coder added 1 commit 2026-07-05 23:36:06 +03:00
The {search-queue} BullMQ queue had producers on every page/space/workspace change
but NO consumer/@Processor — it lives in Docmost's EE edition (external search
drivers), never in this fork. Search works independently via the pages tsvector DB
trigger; the queue was pure dead weight, growing forever (1902 stuck jobs in Redis,
the first real hit of the #355 queue-growing alert — which fired correctly).

Remove the plumbing:
- the 3 producers: drop @InjectQueue(SEARCH_QUEUE) + every searchQueue.add(...) from
  page/space/workspace.listener.ts (and the isTypesense() gate that only wrapped the
  search enqueue). page.listener.handlePageUpdated did ONLY the search enqueue, so its
  @OnEvent(PAGE_UPDATED) handler is removed; the other handlers keep their aiQueue.add.
- the registration (queue.module.ts) and the metrics injection + 'search' depth-metric
  entry (metrics-bull.service.ts).
- the constants: QueueName.SEARCH_QUEUE + the 6 unused SEARCH_INDEX_* QueueJob members
  (grep-confirmed unreferenced). Shared QueueJob members (PAGE_*, SPACE_DELETED,
  WORKSPACE_DELETED — used by the AI queue / embedding/history/notification processors)
  are kept.

Search (tsvector trigger, search.service) and the PAGE_UPDATED websocket listener are
untouched. Verified: apps/server tsc --noEmit 0 errors; 6 spec suites / 52 tests green.

Ops (maintainer, out of code scope): one-time Redis cleanup
`redis-cli --scan --pattern "bull:{search-queue}:*" | xargs -r redis-cli del`, then
confirm bullmq_queue_depth{queue="search"} stays 0 (the metric no longer injects it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent_coder added the review/needs label 2026-07-05 23:36:07 +03:00
Collaborator

🤖 Авто-ревью · #380 (fix(queue): убрать мёртвую очередь {search-queue} (#379)), голова 97bd554c

Вердикт: PASS — удаление чистое, полное и безопасное; поиск от очереди не зависит и продолжает работать. Ставлю review/approved.

Веер 9 аспектов (5 субагентов + 4 напрямую) — ни одного DO/ESCALATE. Всё сверено с кодом; ключевые утверждения PR подтверждены.

Что проверено (адверсариально)

  • Поиск НЕ ломается — подтверждено. Дефолтный драйвер database (environment.service.ts:305) ищет по колонке pages.tsv (search.service.tsts_rank(tsv, to_tsquery(...))), а tsv поддерживается DB-триггером pages_tsvector_trigger() (migrations/20240324T086800-pages-tsvector-trigger.ts + .../20250729T...-update-tsvector, BEFORE INSERT OR UPDATE ON pages). Удалённый searchQueue.add этот путь никогда не питал. Объективка: jest src/core/search3 suites / 18 tests passed.
  • Консьюмера в этом репо нет — подтверждено. ee/ в репо отсутствует; ни @Processor({search-queue}), ни любого консьюмера нет. Продюсеры энкьюили в никуда (1902 залипших джоба — корректное срабатывание алерта queue-growing из #355). Typesense EE-гейтед и на запись, и на чтение (search.controller.ts searchTypesenserequire('../../ee/typesense/...') → бросает BadRequestException, т.к. ee/ нет), так что драйвер typesense в этой сборке был сломан ДО PR и остаётся так же — PR лишь прекращает рост очереди. Поведение не изменено.
  • Удаление handlePageUpdated безопасно. EventName.PAGE_UPDATED по-прежнему эмитится (page.repo.ts:177) и имеет живого консьюмера — ws/listeners/page-ws.listener.ts:78 (@OnEvent(PAGE_UPDATED), WS-бродкаст rename/icon). Удалённый хендлер делал ТОЛЬКО search-энкью — других сайд-эффектов не потеряно (AI-энкью на PAGE_UPDATED и не было; на created/deleted/soft-deleted/restored aiQueue.add сохранён).
  • Чистота удаления. tsc -p tsconfig.build.json --noEmit0 ошибок. Ноль остаточных ссылок на SEARCH_QUEUE/searchQueue/SEARCH_INDEX_* по всему репо. DI консистентен: queue.module.ts регистрирует 9 очередей = metrics-bull инжектит ровно те же 9 (массив {label,queue} выровнен, off-by-one нет); EnvironmentService корректно убран из 3 листенеров (его единственное использование — isTypesense() — удалено) и корректно ОСТАВЛЕН в metrics-bull (там он для getRedisUrl()). Ни одного повисшего импорта. Спеки на удалённые символы не ссылаются — сломанных тестов нет.
Вне scope (кандидаты на отдельный issue, НЕ блокеры) + что судил напрямую

Вне scope (до-существующее, PR не ухудшает — на отдельный issue):

  • Мёртвые константы QueueJob.SEARCH_REMOVE_PAGE/ASSET/FACE + TYPESENSE_FLUSH оставлены. Проверено на родительском коммите (97bd554c^): они были орфанами уже до PR (только самоопределение, ноль продюсеров) — то есть это НЕ внесённая PR-ом несогласованность. SEARCH_INDEX_* убраны потому что это имена джобов удаляемой очереди; SEARCH_REMOVE_*/TYPESENSE_FLUSH — отдельные до-существующие орфаны, к продюсерам очереди не привязаны. Оставить их безвредно (плейн-строки enum, ни к чему не биндятся). Бонус: их строковые значения уже перепутаны (SEARCH_REMOVE_FACE='search-remove-comment') — тоже до-существующее. Стоит подмести отдельно.
  • Драйвер typesense в CE-сборке: search.controller.ts всё ещё роутит на searchTypesense (бросает, ee/ нет), а environment.validation.ts всё ещё принимает SEARCH_DRIVER='typesense' (@IsIn). До-существующее, PR не трогает и не ухудшает; решить судьбу throw-only typesense-пути — отдельной задачей.

Судил напрямую (аспекты, тривиально чистые для dead-code-удаления): security — новой поверхности нет (только удаление); simplification — код стал проще; documentation — публичных API/доков не меняет; architecture — структурных решений нет, удаление изолировано в queue+listeners.

Веер 9 аспектов, все LGTM; DB-триггер и независимость поиска воспроизвёл сам (jest 18/18), tsc зелёный. Единственная заметка — до-существующие мёртвые константы — ниже DROP-floor и вне scope. Ветка чистая, можно мёржить.

## 🤖 Авто-ревью · #380 (fix(queue): убрать мёртвую очередь {search-queue} (#379)), голова `97bd554c` **Вердикт: PASS** ✅ — удаление чистое, полное и безопасное; поиск от очереди не зависит и продолжает работать. Ставлю review/approved. Веер 9 аспектов (5 субагентов + 4 напрямую) — ни одного DO/ESCALATE. Всё сверено с кодом; ключевые утверждения PR подтверждены. ### Что проверено (адверсариально) - **Поиск НЕ ломается — подтверждено.** Дефолтный драйвер `database` (`environment.service.ts:305`) ищет по колонке `pages.tsv` (`search.service.ts` → `ts_rank(tsv, to_tsquery(...))`), а `tsv` поддерживается **DB-триггером** `pages_tsvector_trigger()` (`migrations/20240324T086800-pages-tsvector-trigger.ts` + `.../20250729T...-update-tsvector`, `BEFORE INSERT OR UPDATE ON pages`). Удалённый `searchQueue.add` этот путь никогда не питал. Объективка: jest `src/core/search` — **3 suites / 18 tests passed**. - **Консьюмера в этом репо нет — подтверждено.** `ee/` в репо **отсутствует**; ни `@Processor({search-queue})`, ни любого консьюмера нет. Продюсеры энкьюили в никуда (1902 залипших джоба — корректное срабатывание алерта `queue-growing` из #355). Typesense EE-гейтед и на запись, и на чтение (`search.controller.ts` `searchTypesense` → `require('../../ee/typesense/...')` → бросает `BadRequestException`, т.к. `ee/` нет), так что драйвер `typesense` в этой сборке был сломан ДО PR и остаётся так же — PR лишь прекращает рост очереди. Поведение не изменено. - **Удаление `handlePageUpdated` безопасно.** `EventName.PAGE_UPDATED` по-прежнему эмитится (`page.repo.ts:177`) и имеет живого консьюмера — `ws/listeners/page-ws.listener.ts:78` (`@OnEvent(PAGE_UPDATED)`, WS-бродкаст rename/icon). Удалённый хендлер делал ТОЛЬКО search-энкью — других сайд-эффектов не потеряно (AI-энкью на PAGE_UPDATED и не было; на created/deleted/soft-deleted/restored `aiQueue.add` сохранён). - **Чистота удаления.** `tsc -p tsconfig.build.json --noEmit` — **0 ошибок**. Ноль остаточных ссылок на `SEARCH_QUEUE`/`searchQueue`/`SEARCH_INDEX_*` по всему репо. DI консистентен: `queue.module.ts` регистрирует 9 очередей = `metrics-bull` инжектит ровно те же 9 (массив `{label,queue}` выровнен, off-by-one нет); `EnvironmentService` корректно убран из 3 листенеров (его единственное использование — `isTypesense()` — удалено) и корректно ОСТАВЛЕН в `metrics-bull` (там он для `getRedisUrl()`). Ни одного повисшего импорта. Спеки на удалённые символы не ссылаются — сломанных тестов нет. <details> <summary>Вне scope (кандидаты на отдельный issue, НЕ блокеры) + что судил напрямую</summary> **Вне scope (до-существующее, PR не ухудшает — на отдельный issue):** - Мёртвые константы `QueueJob.SEARCH_REMOVE_PAGE/ASSET/FACE` + `TYPESENSE_FLUSH` оставлены. Проверено на родительском коммите (`97bd554c^`): они были орфанами **уже до** PR (только самоопределение, ноль продюсеров) — то есть это НЕ внесённая PR-ом несогласованность. `SEARCH_INDEX_*` убраны потому что это имена джобов удаляемой очереди; `SEARCH_REMOVE_*`/`TYPESENSE_FLUSH` — отдельные до-существующие орфаны, к продюсерам очереди не привязаны. Оставить их безвредно (плейн-строки enum, ни к чему не биндятся). Бонус: их строковые значения уже перепутаны (`SEARCH_REMOVE_FACE='search-remove-comment'`) — тоже до-существующее. Стоит подмести отдельно. - Драйвер `typesense` в CE-сборке: `search.controller.ts` всё ещё роутит на `searchTypesense` (бросает, `ee/` нет), а `environment.validation.ts` всё ещё принимает `SEARCH_DRIVER='typesense'` (`@IsIn`). До-существующее, PR не трогает и не ухудшает; решить судьбу throw-only typesense-пути — отдельной задачей. **Судил напрямую (аспекты, тривиально чистые для dead-code-удаления):** security — новой поверхности нет (только удаление); simplification — код стал проще; documentation — публичных API/доков не меняет; architecture — структурных решений нет, удаление изолировано в queue+listeners. </details> <sub>Веер 9 аспектов, все LGTM; DB-триггер и независимость поиска воспроизвёл сам (jest 18/18), tsc зелёный. Единственная заметка — до-существующие мёртвые константы — ниже DROP-floor и вне scope. Ветка чистая, можно мёржить.</sub> <!-- state:review reviewed_head=97bd554cb5 round=1 verdict=pass -->
agent_reviewer added review/approved and removed review/needs labels 2026-07-05 23:44:01 +03:00
vvzvlad merged commit 0665fcb630 into develop 2026-07-05 23:44:58 +03:00
Sign in to join this conversation.