[backend][celery] Beat-таски refresh_quarter_price_index_chain и etl_newbuilding_crossload не зарегистрированы на воркере (отсутствуют в include) — молча никогда не выполняются #1656

Closed
opened 2026-06-16 18:47:07 +00:00 by bot-backend · 0 comments
Collaborator

Severity: high · Категория: concurrency/idempotency-config · Файл: backend/app/workers/celery_app.py:50-82

Где: backend/app/workers/celery_app.py:50-82 (список include). Воркер регистрирует таски ТОЛЬКО через статический include=[...]; в коде нет autodiscover_tasks(), conf.imports, config_from_object — проверено grep по app/. Два модуля, диспетчеризуемые beat'ом, отсутствуют в include и не импортируются транзитивно ни одним включённым модулем, ни beat_schedule.py, ни lifecycle.py (tasks/init.py пуст, 0 байт):

  • beat_schedule.py:319-323 → task 'tasks.refresh_quarter_price_index.refresh_quarter_price_index_chain' (ежемесячно 5-го, 05:00 МСК), queue='celery'. Модуль app.workers.tasks.refresh_quarter_price_index нигде не импортируется кроме самого себя.
  • beat_schedule.py:422-426 → task 'tasks.etl_newbuilding_crossload.etl_newbuilding_crossload' (ночью 03:30 МСК), queue='celery'. Импортируется лениво только в FastAPI-хендлере admin_scrape.py:1077 (web-процесс), не на воркере.
    Воркер: 'celery -A app.workers.celery_app worker' (docker-compose.yml:72; prod.yml:128 --queues=celery,scrape_kn,geo) слушает очередь celery, поэтому beat-сообщения ДОХОДЯТ до воркера, но имена тасок там не зарегистрированы (декоратор @celery_app.task регистрирует только при импорте модуля в процессе) → Celery отвергает их как 'Received unregistered task of type ...' и отбрасывает сообщение. Для сравнения, app.workers.tasks.developer_registry_refresh (добавлен 2026-06-13) корректно дописан в include (строка 81); эти два старых модуля просто забыли.
    Импакт: (1) mv_quarter_price_per_m2 / mv_quarter_price_index (#762) никогда не пересчитываются по расписанию → ценовой индекс молча устаревает месяц за месяцем; (2) newbuilding_listings никогда не обновляется из tradein.houses (#976). Ручной триггер POST /api/v1/admin/scrape/newbuilding-crossload тоже падает идентично — он лишь apply_async() в ту же незарегистрированную очередь воркера. monitor_beat_tasks=True (celery_app.py:35) отслеживает только факт диспетчеризации beat'ом, не выполнение, поэтому проблема видна лишь по ERROR-строкам 'unregistered task' в логах воркера. Подтверждает unintended-характер комментарий docker-compose.prod.yml:129 ('worker запускает etl_newbuilding_crossload task').
    Фикс: добавить в include (celery_app.py:50-82) две строки: 'app.workers.tasks.refresh_quarter_price_index' и 'app.workers.tasks.etl_newbuilding_crossload'. После деплоя проверить логи воркера на отсутствие 'unregistered task' и убедиться, что обе MV и newbuilding_listings обновляются по расписанию.

Почему баг: Celery workers only execute tasks whose modules were imported at startup (here: exclusively the include list). A task name that beat sends but the worker never imported is treated as unregistered and dropped. Consequences: (1) mv_quarter_price_per_m2 and mv_quarter_price_index (issue #762) are never refreshed by the scheduled chain → the price index served to users silently goes stale month after month; (2) newbuilding_listings is never cross-loaded from tradein.houses → the new-building dataset silently never updates. Even manual triggering of crossload via POST /api/v1/admin/scrape/newbuilding-crossload only enqueues (apply_async) — execution still happens on the worker, which also lacks the registration, so the manual path fails identically. monitor_beat_tasks=True (celery_app.py:36) tracks that beat dispatched the job, not that it ran, so this can pass unnoticed except for ERROR-level 'unregistered task' lines in worker logs.

Как чинить: Add the two missing modules to the include list in celery_app.py:
"app.workers.tasks.etl_newbuilding_crossload",
"app.workers.tasks.refresh_quarter_price_index",
Alternatively switch to celery_app.autodiscover_tasks(['app.workers.tasks']) so future task modules can't be silently omitted from the worker registry. After the fix, verify with celery -A app.workers.celery_app inspect registered that both task names appear.


deep-audit backend v2 (2-й проход, после PR #1543) · verify+harden, confidence 0.9 · unit B46

**Severity:** high · **Категория:** concurrency/idempotency-config · **Файл:** `backend/app/workers/celery_app.py:50-82` Где: backend/app/workers/celery_app.py:50-82 (список include). Воркер регистрирует таски ТОЛЬКО через статический include=[...]; в коде нет autodiscover_tasks(), conf.imports, config_from_object — проверено grep по app/. Два модуля, диспетчеризуемые beat'ом, отсутствуют в include и не импортируются транзитивно ни одним включённым модулем, ни beat_schedule.py, ни lifecycle.py (tasks/__init__.py пуст, 0 байт): - beat_schedule.py:319-323 → task 'tasks.refresh_quarter_price_index.refresh_quarter_price_index_chain' (ежемесячно 5-го, 05:00 МСК), queue='celery'. Модуль app.workers.tasks.refresh_quarter_price_index нигде не импортируется кроме самого себя. - beat_schedule.py:422-426 → task 'tasks.etl_newbuilding_crossload.etl_newbuilding_crossload' (ночью 03:30 МСК), queue='celery'. Импортируется лениво только в FastAPI-хендлере admin_scrape.py:1077 (web-процесс), не на воркере. Воркер: 'celery -A app.workers.celery_app worker' (docker-compose.yml:72; prod.yml:128 --queues=celery,scrape_kn,geo) слушает очередь celery, поэтому beat-сообщения ДОХОДЯТ до воркера, но имена тасок там не зарегистрированы (декоратор @celery_app.task регистрирует только при импорте модуля в процессе) → Celery отвергает их как 'Received unregistered task of type ...' и отбрасывает сообщение. Для сравнения, app.workers.tasks.developer_registry_refresh (добавлен 2026-06-13) корректно дописан в include (строка 81); эти два старых модуля просто забыли. Импакт: (1) mv_quarter_price_per_m2 / mv_quarter_price_index (#762) никогда не пересчитываются по расписанию → ценовой индекс молча устаревает месяц за месяцем; (2) newbuilding_listings никогда не обновляется из tradein.houses (#976). Ручной триггер POST /api/v1/admin/scrape/newbuilding-crossload тоже падает идентично — он лишь apply_async() в ту же незарегистрированную очередь воркера. monitor_beat_tasks=True (celery_app.py:35) отслеживает только факт диспетчеризации beat'ом, не выполнение, поэтому проблема видна лишь по ERROR-строкам 'unregistered task' в логах воркера. Подтверждает unintended-характер комментарий docker-compose.prod.yml:129 ('worker запускает etl_newbuilding_crossload task'). Фикс: добавить в include (celery_app.py:50-82) две строки: 'app.workers.tasks.refresh_quarter_price_index' и 'app.workers.tasks.etl_newbuilding_crossload'. После деплоя проверить логи воркера на отсутствие 'unregistered task' и убедиться, что обе MV и newbuilding_listings обновляются по расписанию. **Почему баг:** Celery workers only execute tasks whose modules were imported at startup (here: exclusively the include list). A task name that beat sends but the worker never imported is treated as unregistered and dropped. Consequences: (1) mv_quarter_price_per_m2 and mv_quarter_price_index (issue #762) are never refreshed by the scheduled chain → the price index served to users silently goes stale month after month; (2) newbuilding_listings is never cross-loaded from tradein.houses → the new-building dataset silently never updates. Even manual triggering of crossload via POST /api/v1/admin/scrape/newbuilding-crossload only enqueues (apply_async) — execution still happens on the worker, which also lacks the registration, so the manual path fails identically. monitor_beat_tasks=True (celery_app.py:36) tracks that beat *dispatched* the job, not that it ran, so this can pass unnoticed except for ERROR-level 'unregistered task' lines in worker logs. **Как чинить:** Add the two missing modules to the include list in celery_app.py: "app.workers.tasks.etl_newbuilding_crossload", "app.workers.tasks.refresh_quarter_price_index", Alternatively switch to celery_app.autodiscover_tasks(['app.workers.tasks']) so future task modules can't be silently omitted from the worker registry. After the fix, verify with `celery -A app.workers.celery_app inspect registered` that both task names appear. --- <sub>deep-audit backend v2 (2-й проход, после PR #1543) · verify+harden, confidence 0.9 · unit B46</sub>
bot-backend added the
week ревью 1
label 2026-06-16 18:47:07 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1656
No description provided.