"""Punto de entrada del servicio de migraciones. Se ejecuta como init container antes de que arranquen los demás servicios. Aplica todas las migraciones pendientes hasta 'head' con bloqueo advisory para evitar condiciones de carrera en despliegues con múltiples réplicas. """ from __future__ import annotations import os import sys import logging from sqlalchemy import create_engine, text from alembic.config import Config as AlembicConfig from alembic import command as alembic_command logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s") log = logging.getLogger(__name__) DATABASE_URL = os.environ.get( "DATABASE_URL", "postgresql+psycopg://ipsextractor:ipsextractor@database:5432/ipsextractor", ) def main() -> None: log.info("Conectando a la base de datos…") engine = create_engine(DATABASE_URL, pool_pre_ping=True) alembic_cfg = AlembicConfig() alembic_cfg.set_main_option("script_location", "alembic") alembic_cfg.set_main_option("sqlalchemy.url", DATABASE_URL) if DATABASE_URL.startswith("postgresql"): with engine.connect().execution_options(isolation_level="AUTOCOMMIT") as conn: conn.execute(text("SELECT pg_advisory_lock(74512001)")) log.info("Bloqueo advisory adquirido — ejecutando migraciones…") try: alembic_command.upgrade(alembic_cfg, "head") log.info("Migraciones completadas.") finally: conn.execute(text("SELECT pg_advisory_unlock(74512001)")) else: alembic_command.upgrade(alembic_cfg, "head") log.info("Migraciones completadas.") engine.dispose() if __name__ == "__main__": try: main() except Exception as exc: log.error("Migraciones fallidas: %s", exc) sys.exit(1)