from alembic import context from sqlalchemy import engine_from_config, pool, text from app.config import settings from app.models import Base config = context.config config.set_main_option("sqlalchemy.url", settings.database_url.replace("%", "%%")) target_metadata = Base.metadata MIGRATION_LOCK = 703000 # advisory-lock: одна реплика мигрирует, остальные ждут и видят актуальную схему def run(): engine = engine_from_config(config.get_section(config.config_ini_section), prefix="sqlalchemy.", poolclass=pool.NullPool) with engine.connect() as lock_conn: # отдельное соединение держит блокировку до конца миграций lock_conn.execute(text("SELECT pg_advisory_lock(:k)"), {"k": MIGRATION_LOCK}) with engine.connect() as conn: context.configure(connection=conn, target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() lock_conn.execute(text("SELECT pg_advisory_unlock(:k)"), {"k": MIGRATION_LOCK}) lock_conn.commit() run()