python-trio / triopg

PostgreSQL client for Trio based on asyncpg
Other
45 stars 8 forks source link

AttributeError: 'NoneType' object has no attribute 'run_aio_coroutine' #16

Open SamP20 opened 3 years ago

SamP20 commented 3 years ago

I'm not sure whether this is a triopg, quart_trio, trio_asyncio or a trio issue. I'm trying to create and store a database connection using Quart's while_serving handler like so:

from quart_trio import QuartTrio
import trio
import triopg

app = QuartTrio(__name__)
@app.while_serving
async def create_db():
    async with triopg.connect("dbname=my_database user=my_user") as conn:
        app.db = conn
        yield

app.run()

However this is resulting in the following error:

Running on http://127.0.0.1:5000 (CTRL + C to quit)
[2021-09-18 19:22:48,223] Running on http://127.0.0.1:5000 (CTRL + C to quit)
Traceback (most recent call last):
  File "<snip>/.venv/lib/python3.9/site-packages/quart_trio/asgi.py", line 117, in __call__
    await self.app.startup()
  File "<snip>/.venv/lib/python3.9/site-packages/quart/app.py", line 1757, in startup
    await gen.__anext__()
  File "<snip>/main.py", line 11, in create_db
    async with triopg.connect("dbname=my_database user=my_user") as conn:
  File "<snip>/.venv/lib/python3.9/site-packages/triopg/_triopg.py", line 195, in __aenter__
    self._asyncpg_conn = await trio_asyncio.aio_as_trio(
  File "<snip>/.venv/lib/python3.9/site-packages/trio_asyncio/_adapter.py", line 54, in __call__
    return await self.loop.run_aio_coroutine(f)
AttributeError: 'NoneType' object has no attribute 'run_aio_coroutine'

I did find this comment, however it doesn't quite seem relavent here https://github.com/python-trio/trio-asyncio/issues/110#issuecomment-769983648

It could be that I'm mis-using these libraries, in which case it would be awesome if someone could point me in the right direction. Currently I'm creating a single connection for the entire app, however in practice I'd like to use the connection pool in a similar way.

jakobcornell commented 2 years ago

I just got this error and was able to fix it by starting the main task using trio_asyncio.run as the readme example shows instead of trio.run. Makes sense to me because the library wraps the asyncio library asyncpg. Not familiar with Quart, but my guess is the solution in this case is to find some way for Quart to start its main task using trio_asyncio.

touilleMan commented 2 years ago

@SamP20 as @jakobcornell says, trio_asyncio can lead to tricky lifetime issues: typically you may have a coroutine creating the trio_asyncio scope, and a coroutine from a parent scope (typically what is done with @app.while_serving) that uses the component needing trio_asyncio. Then when the coroutine with the trio_asyncio scope stops things get messy 😄

So the best strategy it to try to have trio_asyncio scope as high as possible (and if possible uses trio_asyncio.run instead of trio.run !)