进行Alembic升级的试运行

时间:2018-07-27 11:26:40

标签: python sql alembic

有时alembic upgrade head可能在运行时针对我的生产数据库失败,即使它对我的测试数据库也可以正常工作。例如,迁移可能会向我的测试环境中以前不包含NOT NULL的列中添加NULL约束,而 did 包含NULL在生产中。

在计划部署时,最好能够在运行迁移之前检查其是否可以干净地应用。对于不支持事务性DDL(在事务中进行模式更改)的数据库(例如MySQL),这是不可能的,但是对于确实支持事务性DDL的数据库(例如PostgreSQL),原则上应该是可行的。 Alembic可以尝试在事务中执行升级,然后回滚。

Alembic是否对此类功能有任何支持?如果没有,是否有一些骇人听闻的方法可以实现?

2 个答案:

答案 0 :(得分:6)

一个允许这样做的简单技巧是将有条件回滚注入到run_migrations_online中的env.py函数中,该函数仅在存在表示我们要空运行的标志时才触发。

如果您的文件已被修改,请回想一下run_migrations_online创建的alembic init函数的默认实现,如下所示:

def run_migrations_online():
    """Run migrations in 'online' mode.

    In this scenario we need to create an Engine
    and associate a connection with the context.

    """
    connectable = engine_from_config(
        config.get_section(config.config_ini_section),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
        context.configure(
            connection=connection, target_metadata=target_metadata
        )

        with context.begin_transaction():
            context.run_migrations()

请注意:

  • __enter__的{​​{1}}方法(我们已经在默认实现中调用了该方法)为我们提供了具有context.begin_transaction()方法的事务对象,并且
  • 我们的rollback()对象具有一个get_x_argument方法,我们可以用来支持将自定义参数传递给context命令。

因此,进行以下较小的更改(除了添加alembic和最后三行之外,以下所有内容都是相同的),我们可以使用试运行功能:

as transaction

现在,要进行试运行,请执行以下操作:

def run_migrations_online():
    """Run migrations in 'online' mode.

    In this scenario we need to create an Engine
    and associate a connection with the context.

    """
    connectable = engine_from_config(
        config.get_section(config.config_ini_section),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
        context.configure(
            connection=connection, target_metadata=target_metadata
        )
        with context.begin_transaction() as transaction:
            context.run_migrations()
            if 'dry-run' in context.get_x_argument():
                print('Dry-run succeeded; now rolling back transaction...')
                transaction.rollback()

要进行实际运行,只需执行以下操作:

alembic -x dry-run upgrade head

像以前一样。

答案 1 :(得分:0)

您可以创建自己的Alembic配置,脚本目录和环境上下文。至关重要的是,它应该已经传递了一个已经创建的连接,您可以在完成空运行后回滚。

engine = sa.create_engine(url)
session = Session(bind=engine)
try:
    alembic_config = AlembicConfig(config_args={...})
    alembic_config.attributes.update({"connection": session.connection()})
    script_directory = ScriptDirectory.from_config(alembic_config)
    env_context = EnvironmentContext(
        alembic_config,
        script_directory,
        fn=lambda rev, context: script_directory._upgrade_revs("head", rev),
        as_sql=False,
    )
    env_context.configure(connection=session.connection())
    env_context.run_migrations()

finally:
    session.rollback()
    session.close()