diff --git a/src/alpine_bits_python/api.py b/src/alpine_bits_python/api.py index b019f12..16b82b3 100644 --- a/src/alpine_bits_python/api.py +++ b/src/alpine_bits_python/api.py @@ -275,17 +275,18 @@ async def lifespan(app: FastAPI): elif hotel_id and not push_endpoint: _LOGGER.info("Hotel %s has no push_endpoint configured", hotel_id) - # Run database migrations first (only primary worker to avoid race conditions) + # Create tables first (all workers) + # This ensures tables exist before migrations try to alter them + async with engine.begin() as conn: + await conn.run_sync(Base.metadata.create_all) + _LOGGER.info("Database tables checked/created at startup.") + + # Run migrations after tables exist (only primary worker for race conditions) if is_primary: await run_all_migrations(engine) else: _LOGGER.info("Skipping migrations (non-primary worker)") - # Create tables (all workers) - async with engine.begin() as conn: - await conn.run_sync(Base.metadata.create_all) - _LOGGER.info("Database tables checked/created at startup.") - # Hash any existing customers (only in primary worker to avoid race conditions) if is_primary: async with AsyncSessionLocal() as session: diff --git a/src/alpine_bits_python/migrations.py b/src/alpine_bits_python/migrations.py index 68a2363..5702e17 100644 --- a/src/alpine_bits_python/migrations.py +++ b/src/alpine_bits_python/migrations.py @@ -99,7 +99,7 @@ async def migrate_add_room_types(engine: AsyncEngine) -> None: async def run_all_migrations(engine: AsyncEngine) -> None: """Run all pending migrations. - This function should be called at app startup, before Base.metadata.create_all. + This function should be called at app startup, after Base.metadata.create_all. Each migration function should be idempotent (safe to run multiple times). """ _LOGGER.info("Starting database migrations...")