/ api-gateway / app / migrations.py
migrations.py
 1  """Migration runner for application startup."""
 2  import logging
 3  from alembic import command
 4  from alembic.config import Config
 5  import os
 6  import time
 7  from sqlalchemy import create_engine, text
 8  from sqlalchemy.exc import OperationalError
 9  
10  logger = logging.getLogger(__name__)
11  
12  
13  def wait_for_db(max_retries=30, retry_delay=2):
14      """Wait for database to be ready before running migrations."""
15      database_url = os.getenv(
16          "DATABASE_URL",
17          "postgresql://smeops:change-me@postgres:5432/smeops"
18      )
19      
20      for attempt in range(max_retries):
21          try:
22              engine = create_engine(database_url, pool_pre_ping=True)
23              with engine.connect() as conn:
24                  conn.execute(text("SELECT 1"))
25              logger.info("Database is ready")
26              return True
27          except OperationalError as e:
28              if attempt < max_retries - 1:
29                  logger.warning(f"Database not ready (attempt {attempt + 1}/{max_retries}): {e}")
30                  time.sleep(retry_delay)
31              else:
32                  logger.error(f"Database not ready after {max_retries} attempts")
33                  raise
34      return False
35  
36  
37  def run_migrations():
38      """Run Alembic migrations on application startup."""
39      try:
40          # Wait for database to be ready
41          wait_for_db()
42          
43          # Get path to alembic.ini
44          alembic_cfg = Config(os.path.join(os.path.dirname(os.path.dirname(__file__)), "alembic.ini"))
45          
46          # Override sqlalchemy.url with environment variable
47          alembic_cfg.set_main_option("sqlalchemy.url", os.getenv(
48              "DATABASE_URL",
49              "postgresql://smeops:change-me@postgres:5432/smeops"
50          ))
51          
52          logger.info("Running database migrations...")
53          command.upgrade(alembic_cfg, "head")
54          logger.info("Database migrations completed successfully")
55      except Exception as e:
56          logger.error(f"Failed to run database migrations: {e}")
57          raise