gendesign/backend/app/workers/tasks/refresh_layout_velocity.py
bot-backend 6982255fb3
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m54s
CI / backend-tests (pull_request) Successful in 17m0s
fix(workers): убрать max_retries, который ничего не делает (#2464)
11 тасок объявляли `max_retries=2`, но ретраи не реализовывали: ни
`autoretry_for` в декораторе, ни вызова `self.retry()` в теле. Celery в
таком виде параметр не применяет — при исключении таска падает с первой
попытки. Читающий код видит «до 3 попыток», а их одна.

Убран `max_retries` у: cbr_macro_sync, rosstat_macro_sync,
developer_registry_refresh, location_refresh, mv_sales_tracker_refresh,
refresh_analytics, refresh_layout_velocity, refresh_quarter_price_index,
scrape_objective.sync_objective_group, supply_layers_refresh,
scrape_kn.scrape_kn_region. Заодно убран `bind=True` там, где `self` не
использовался вовсе; в `scrape_kn_region` он оставлен — `self.request.id`
пишется в kn_scrape_log.

Не тронуты и не должны быть: `resume_kn_run` (max_retries=12 +
настоящий self.retry()), `nspd_sync`/`scrape_cadastre` (autoretry_for),
`nspd_geo`/`objective_etl` (max_retries=0 — честное «ретраев нет»).

Гейт `test_2464_retry_config_is_real.py` разбирает AST всех модулей
`app/workers/tasks/` и требует: если декоратор объявляет ненулевой
max_retries, в нём есть autoretry_for либо в теле функции есть
self.retry(). Три таски из одиннадцати гейт нашёл сверх списка эпика.

Проверка гейта: с фиксом зелено, при возврате `max_retries=2` в
supply_layers_refresh — красно с указанием на эту таску. Плюс два
контроля: гейт видит ≥20 тасок (не молчит из-за пустой выборки) и
признаёт обе законные формы ретраев.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 17:17:38 +05:00

51 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Celery task: refresh mv_layout_velocity (питает «лучшие планировки» best_layouts).
Scheduled via hardcoded beat entry in workers/beat_schedule.py:
'refresh-layout-velocity' — weekly on Sunday at 03:00 MSK.
Стоит в «ночном» окне воскресенья, отдельно от monday-кластера тяжёлых
site_finder-рефрешей (supply-layers / ird / gknspecial / cbr и т.д.), чтобы
не конкурировать с ними за БД/CPU.
Issue: #1666 (рефреш не был подключён в beat → данные best_layouts молча
устаревали в проде). MV-источник: #113 (PR B, mv_layout_velocity → best_layouts).
"""
from __future__ import annotations
import logging
from typing import Any
from app.core.db import SessionLocal
from app.services.site_finder.layout_velocity_refresh import refresh_layout_velocity
from app.workers.celery_app import celery_app
logger = logging.getLogger(__name__)
# Ретраев здесь нет, и параметров, обещающих их, быть не должно (#2464). Стояло
# `bind=True, max_retries=2`, но self не использовался, self.retry() не вызывался и
# autoretry_for задан не был — конфигурация не имела эффекта. Где ретраи нужны, они
# задаются явно: autoretry_for (nspd_sync, scrape_cadastre) или self.retry()
# (scrape_kn.resume_kn_run). Где их сознательно нет — пишется max_retries=0 с
# пояснением (nspd_geo, objective_etl.import_anton_objective).
@celery_app.task(
name="tasks.refresh_layout_velocity.refresh_layout_velocity",
)
def refresh_layout_velocity_task() -> dict[str, Any]:
"""REFRESH MATERIALIZED VIEW mv_layout_velocity (best_layouts, #113 / #1666).
MV рефрешится CONCURRENTLY (non-blocking, требует unique-индекс
mv_layout_velocity_pk); сервис сам падает в non-concurrent при unpopulated MV.
Returns result dict for Celery task result store / logging.
"""
db = SessionLocal()
try:
count = refresh_layout_velocity(db, concurrently=True)
logger.info("refresh_layout_velocity: completed, mv rows=%d", count)
return {"status": "ok", "mv_layout_velocity_rows": count}
except Exception as e:
logger.exception("refresh_layout_velocity failed: %s", e)
raise
finally:
db.close()