gendesign/backend/app/workers/tasks/refresh_analytics.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

52 lines
2.3 KiB
Python
Raw Permalink 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 tasks для регулярного refresh аналитических метрик.
Расписание задаётся в celery_app.beat_schedule. Сейчас:
- refresh_ekb_districts_medians — раз в месяц 5-го числа в 04:00 МСК
(после публикации последнего rosreestr-квартала + NSPD beat-cycle).
"""
from __future__ import annotations
import logging
from typing import Any
from app.core.db import SessionLocal
from app.services.analytics_refresh import refresh_ekb_districts_median
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_analytics.refresh_ekb_districts_medians",
)
def refresh_ekb_districts_medians(
window_months: int = 24,
min_deals: int = 50,
) -> dict[str, Any]:
"""Refresh ekb_districts.median_price_per_m2 + mean_price_per_m2.
Лёгкая задача (1-2 секунды на 8 районов), не требует locks.
Запускается ежемесячно. Возвращает результат для аудита (что обновлено).
"""
db = SessionLocal()
try:
rows = refresh_ekb_districts_median(db, window_months=window_months, min_deals=min_deals)
logger.info("refreshed %d districts", len(rows))
return {
"updated_count": len(rows),
"districts": rows,
"window_months": window_months,
"min_deals": min_deals,
}
except Exception as e:
logger.exception("refresh_ekb_districts_medians failed: %s", e)
raise
finally:
db.close()