Unverified Commit 1becb2fa authored by John Davis's avatar John Davis Committed by GitHub
Browse files

Merge pull request #19551 from jdavcs/24.2_migration_edit

[24.2] Provide guidance in case of deadlock during db migration
parents 59186d03 54fc956c
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -542,6 +542,12 @@ After that, run the upgrade script: `./manage_db.sh upgrade`. And you're done!

## Troubleshooting

### Deadlock detected

If you see a deadlock error, that may have been caused by a migration script requiring exclusive access
to a database object, such as a row or a table. To avoid this error, it is recommended to shut down
all Galaxy processes during database migration.

### How to handle migrations.IncorrectVersionError

If you see this error, you'll need to upgrade or downgrade your database *before* upgrading to
@@ -552,4 +558,3 @@ is 181. Please see [this issue](https://github.com/galaxyproject/galaxy/issues/1

#### Please help us improve this page:
If you encounter any migration-related errors or issues, please [open an issue](https://github.com/galaxyproject/galaxy/issues/new?assignees=&labels=&template=bug_report.md&title=), and we will add the solution with any relevant context to this page.
+16 −4
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ from alembic import context
from alembic.script import ScriptDirectory
from alembic.script.base import Script
from sqlalchemy import create_engine
from sqlalchemy.exc import OperationalError

from galaxy.model import Base
from galaxy.model.migrations import (
@@ -111,17 +112,28 @@ def _configure_and_run_migrations_offline(url: str) -> None:
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
    )
    with context.begin_transaction():
        context.run_migrations()
    _run_migrations()


def _configure_and_run_migrations_online(url) -> None:
    engine = create_engine(url)
    with engine.connect() as connection:
        context.configure(connection=connection, target_metadata=target_metadata)
        _run_migrations()
    engine.dispose()


def _run_migrations():
    with context.begin_transaction():
        try:
            context.run_migrations()
    engine.dispose()
        except OperationalError as error:
            if getattr(error.orig, "pgcode", None) == "40P01":  # PostgreSQL DeadlockDetected error detected
                msg = """A deadlock has been detected. This may be due to a database
revision requiring exclusive access to a database object. To avoid this error, it is recommended to
shut down all Galaxy procesess during database migration."""
                log.error(msg)
                raise


def _get_url_from_config() -> str:
+18 −2
Original line number Diff line number Diff line
@@ -6,6 +6,11 @@ Create Date: 2024-10-08 14:08:28.418055

"""

import logging

from alembic import op
from sqlalchemy import text

from galaxy.model.database_object_names import build_index_name
from galaxy.model.migrations.util import (
    alter_column,
@@ -14,6 +19,8 @@ from galaxy.model.migrations.util import (
    transaction,
)

log = logging.getLogger(__name__)

# revision identifiers, used by Alembic.
revision = "9a5207190a4d"
down_revision = "a99a5b52ccb8"
@@ -35,6 +42,15 @@ def upgrade():

def downgrade():
    with transaction():
        drop_index(index_name, table_name)
        alter_column(table_name, column_name, nullable=True)

        stmt = text("SELECT 1 FROM role GROUP BY name HAVING count(*) > 1")
        has_nonunique_values = op.get_bind().scalar(stmt)
        if not has_nonunique_values:
            drop_index(index_name, table_name)
            create_index(index_name, table_name, [column_name], unique=True)
        else:
            msg = f"""This downgrade requires creating a unique index on the `{table_name}.{column_name}` field.
This operation cannot proceed due to the existence of non-unique values in that column, which are the result of Galaxy v24.2 (and above)
operating under normal conditions. The current non-unique index will remain unchanged."""
            log.error(msg)