gendesign/backend/app/services/site_finder/layout_velocity_refresh.py
lekss361 6aa22ef8ba
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 1m43s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 2m50s
Deploy / deploy (push) Successful in 48s
feat(analytics): mv_layout_velocity MV + refresh helper (#113 PR B) (#194)
2026-05-16 08:26:59 +00:00

57 lines
2 KiB
Python

"""Refresh helper for mv_layout_velocity (Issue #113 PR B).
Not scheduled automatically in this PR — intended for manual invocation or
a Celery beat task in a follow-up issue.
Usage example (manual, via psql-connected shell or admin endpoint):
from sqlalchemy.orm import Session
from app.services.site_finder.layout_velocity_refresh import refresh_layout_velocity
count = refresh_layout_velocity(db)
# logs: "mv_layout_velocity refreshed: 459 rows"
"""
from __future__ import annotations
import logging
from sqlalchemy import text
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import Session
logger = logging.getLogger(__name__)
def refresh_layout_velocity(db: Session, *, concurrently: bool = True) -> int:
"""REFRESH MATERIALIZED VIEW mv_layout_velocity.
Args:
db: SQLAlchemy Session (sync).
concurrently: When True, uses REFRESH CONCURRENTLY — non-blocking but
requires the unique index mv_layout_velocity_pk to exist (created
by 94_mv_layout_velocity.sql). Pass False only for the very first
populate or when the MV was just recreated.
Returns:
Row count in the MV after refresh (for observability / alerting).
"""
try:
if concurrently:
db.execute(text("REFRESH MATERIALIZED VIEW CONCURRENTLY mv_layout_velocity"))
else:
db.execute(text("REFRESH MATERIALIZED VIEW mv_layout_velocity"))
db.commit()
except OperationalError as e:
if concurrently and "cannot refresh materialized view" in str(e).lower():
logger.warning(
"CONCURRENTLY failed (MV likely not populated), falling back to non-concurrent"
)
db.rollback()
db.execute(text("REFRESH MATERIALIZED VIEW mv_layout_velocity"))
db.commit()
else:
raise
row = db.execute(text("SELECT COUNT(*) FROM mv_layout_velocity")).first()
count = int(row[0]) if row else 0
logger.info("mv_layout_velocity refreshed: %d rows", count)
return count