0

I'm trying to populate my db with some data and to do so I'm making migrations in which I need to run async uploader that fetch files, parse it to SQLModel and insert to db with SQLAlchemy.

I've initialized alembic as async and my env file is looks like official template from here: https://github.com/sqlalchemy/alembic/blob/main/alembic/templates/async/env.py

Right now my migrations looks like:

def upload_func():
    loop = asyncio.new_event_loop()
    try:
        return loop.run_until_complete(upload_coro())
    finally:
        loop.close()

def upgrade():
    with ThreadPoolExecutor(max_workers=1) as executor:
        future = executor.submit(upload_func)
        future.result()

But it runs ok on first migration and fails on every second migration when it comes to await self.session.execute(stmt) with:

RuntimeError: Task <Task pending coro=<upload_coro() running at /backend/src/alembic/versions/upload_smth.py:32> cb=[_run_until_complete_cb() at /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py:157]> got Future attached to a different loop

So I need do re-run alembic upgrade head multiple times.

What am I doing wrong?

How to get rid of that "Future attached to a different loop"?

Is there any proper way to run coroutines with SQLAlchemy deep down from alembic sync upgrade() function?

Solved down below.

flintpnz
  • 41
  • 3

1 Answers1

0

When you are using async env.py template at https://github.com/sqlalchemy/alembic/blob/main/alembic/templates/async/env.py, which establishes SQLAlchemy's async "greenlet context" around everything that's running, you can run coroutines as:

from sqlalchemy.util import await_only

def upgrade():
    await_only(my_coroutine())
flintpnz
  • 41
  • 3