C1: Materialized view part_vehicle_preview (creación en progreso) - Migración v3.3_materialized_view.sql - catalog_service.py y dashboard/server.py ahora usan la MV - Script refresh_part_vehicle_preview.py + warm_vehicle_cache.py actualizado C2: Fix cache warming script (autónomo) - Auto-re-ejecuta con sudo -u postgres si peer auth falla - Args CLI: --dsn, --batch-size, --ttl, --dry-run C3: CSS dinámico residual extraído - sidebar.js → sidebar.css (nuevo) - pos-utils.js → common.css (nuevo) - Links agregados a 14 templates POS C4: Script de load testing básico - scripts/load_test.py: métricas p50/p95/p99, throughput, errores C5: Documentación actualizada - FASES_IMPLEMENTADAS.md: test count real, FASE 7 completa - performance_audit_2026.md: anexo post-FASE 7, métricas actualizadas A1: Serialización orjson - pos/json_provider.py: DefaultJSONProvider con orjson.dumps/loads - Aplicado a POS app y Dashboard server - Fix indentation error en pos_bp.py Tests: 73/73 pasando
83 lines
2.5 KiB
Python
83 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Refresh the part_vehicle_preview materialized view.
|
|
|
|
Uses REFRESH MATERIALIZED VIEW CONCURRENTLY so reads are not blocked.
|
|
Requires the unique index idx_pvp_part to exist.
|
|
|
|
Usage:
|
|
python3 refresh_part_vehicle_preview.py
|
|
python3 refresh_part_vehicle_preview.py --dsn "postgresql://..."
|
|
|
|
Recommended cron (as postgres user or via systemd timer):
|
|
0 3 * * * /usr/bin/python3 /home/Autopartes/scripts/refresh_part_vehicle_preview.py >> /var/log/nexus-pos/mv_refresh.log 2>&1
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from datetime import datetime
|
|
|
|
import psycopg2
|
|
|
|
DEFAULT_DSN = os.environ.get('MASTER_DB_URL', 'postgresql://postgres@/nexus_autoparts')
|
|
|
|
|
|
def log(msg):
|
|
print(f"[{datetime.now().isoformat(timespec='seconds')}] {msg}", flush=True)
|
|
|
|
|
|
def _connect(dsn):
|
|
return psycopg2.connect(dsn)
|
|
|
|
|
|
def _ensure_connection(dsn):
|
|
try:
|
|
return _connect(dsn)
|
|
except psycopg2.OperationalError as exc:
|
|
err = str(exc).lower()
|
|
if 'peer' in err or 'authentication' in err:
|
|
if os.geteuid() == 0:
|
|
log("ERROR: PostgreSQL peer authentication failed.")
|
|
log(" Run as postgres OS user: sudo -u postgres python3 " + __file__)
|
|
sys.exit(1)
|
|
log("Peer auth failed. Re-running with sudo -u postgres ...")
|
|
cmd = ['sudo', '-u', 'postgres', sys.executable, __file__]
|
|
env = os.environ.copy()
|
|
env['MASTER_DB_URL'] = dsn
|
|
for i, arg in enumerate(sys.argv[1:], start=1):
|
|
if arg in ('--dsn', '-d') and i < len(sys.argv) - 1:
|
|
env['MASTER_DB_URL'] = sys.argv[i + 1]
|
|
ret = subprocess.call(cmd, env=env)
|
|
sys.exit(ret)
|
|
raise
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Refresh part_vehicle_preview MV')
|
|
parser.add_argument('--dsn', '-d', default=DEFAULT_DSN, help='PostgreSQL DSN')
|
|
args = parser.parse_args()
|
|
|
|
log("Starting REFRESH MATERIALIZED VIEW CONCURRENTLY part_vehicle_preview ...")
|
|
conn = _ensure_connection(args.dsn)
|
|
conn.autocommit = True
|
|
cur = conn.cursor()
|
|
start = time.time()
|
|
|
|
try:
|
|
cur.execute("SET statement_timeout = 0;")
|
|
cur.execute("REFRESH MATERIALIZED VIEW CONCURRENTLY part_vehicle_preview;")
|
|
elapsed = time.time() - start
|
|
log(f"Refresh completed in {elapsed:.1f}s")
|
|
except psycopg2.Error as exc:
|
|
log(f"ERROR: {exc}")
|
|
sys.exit(1)
|
|
finally:
|
|
cur.close()
|
|
conn.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|