63 lines
2.3 KiB
Python
63 lines
2.3 KiB
Python
"""Refresh helper for mv_quarter_price_per_m2 (Issue #33 D1).
|
|
|
|
Not scheduled automatically in this PR — intended for manual invocation or
|
|
a Celery beat task in a follow-up issue (Issue #33 PR C).
|
|
|
|
Usage example (manual, via psql-connected shell or admin endpoint):
|
|
from sqlalchemy.orm import Session
|
|
from app.services.site_finder.quarter_price_refresh import refresh_quarter_price
|
|
|
|
count = refresh_quarter_price(db)
|
|
# logs: "mv_quarter_price_per_m2 refreshed: 52492 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_quarter_price(db: Session, *, concurrently: bool = True) -> int:
|
|
"""REFRESH MATERIALIZED VIEW mv_quarter_price_per_m2.
|
|
|
|
Args:
|
|
db: SQLAlchemy Session (sync).
|
|
concurrently: When True, uses REFRESH CONCURRENTLY — non-blocking but
|
|
requires the unique index mv_quarter_price_pk to exist (created by
|
|
95_mv_quarter_price.sql) and the MV to be already populated.
|
|
Pass False only for the very first populate or after MV recreation.
|
|
|
|
Returns:
|
|
Row count in the MV after refresh (for observability / alerting).
|
|
|
|
Raises:
|
|
OperationalError: Re-raised if the error is not the known
|
|
"cannot refresh materialized view concurrently" case.
|
|
"""
|
|
try:
|
|
if concurrently:
|
|
db.execute(text("REFRESH MATERIALIZED VIEW CONCURRENTLY mv_quarter_price_per_m2"))
|
|
else:
|
|
db.execute(text("REFRESH MATERIALIZED VIEW mv_quarter_price_per_m2"))
|
|
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 refresh"
|
|
)
|
|
db.rollback()
|
|
db.execute(text("REFRESH MATERIALIZED VIEW mv_quarter_price_per_m2"))
|
|
db.commit()
|
|
else:
|
|
raise
|
|
|
|
row = db.execute(text("SELECT COUNT(*) FROM mv_quarter_price_per_m2")).first()
|
|
count = int(row[0]) if row else 0
|
|
logger.info("mv_quarter_price_per_m2 refreshed: %d rows", count)
|
|
return count
|