fix: prevent concurrent migrations in multi-worker setup
Add migration version check before running alembic upgrade to prevent multiple uvicorn workers from running migrations simultaneously. - Check current vs head revision before running migrations - Skip migration if already at latest version - Log current and head revision for debugging
This commit is contained in:
@@ -11,7 +11,7 @@ from alembic import op
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision: str = '0003'
|
revision: str = '0003_user_configs'
|
||||||
down_revision: Union[str, None] = '0002_refresh_tokens'
|
down_revision: Union[str, None] = '0002_refresh_tokens'
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import logging
|
|||||||
|
|
||||||
from alembic import command
|
from alembic import command
|
||||||
from alembic.config import Config
|
from alembic.config import Config
|
||||||
|
from alembic.runtime.migration import MigrationContext
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||||
from sqlalchemy.pool import NullPool
|
from sqlalchemy.pool import NullPool
|
||||||
|
|
||||||
@@ -48,6 +49,26 @@ async def init_database(
|
|||||||
|
|
||||||
logger.info("Database connection established.")
|
logger.info("Database connection established.")
|
||||||
|
|
||||||
|
# Check if migrations are already complete
|
||||||
|
def _check_migrations():
|
||||||
|
alembic_cfg = Config(alembic_ini_path)
|
||||||
|
script = command.ScriptDirectory.from_config(alembic_cfg)
|
||||||
|
with engine.connect() as conn:
|
||||||
|
context = MigrationContext.configure(conn)
|
||||||
|
current_rev = context.get_current_revision()
|
||||||
|
head_rev = script.get_current_head()
|
||||||
|
return current_rev == head_rev, current_rev, head_rev
|
||||||
|
|
||||||
|
is_current, current_rev, head_rev = await asyncio.get_event_loop().run_in_executor(
|
||||||
|
None, _check_migrations
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_current:
|
||||||
|
logger.info("Database is already at the latest migration (%s).", head_rev)
|
||||||
|
return True
|
||||||
|
|
||||||
|
logger.info("Current revision: %s, Head revision: %s. Running migrations...", current_rev, head_rev)
|
||||||
|
|
||||||
# Run alembic migrations (sync call in executor)
|
# Run alembic migrations (sync call in executor)
|
||||||
def _run_migrations():
|
def _run_migrations():
|
||||||
alembic_cfg = Config(alembic_ini_path)
|
alembic_cfg = Config(alembic_ini_path)
|
||||||
|
|||||||
Reference in New Issue
Block a user