gino-starlette
gino-starlette copied to clipboard
Cannot release connection after query is canceled.
Expected Behavior
When canceling query, connection should be released back into pool.
Actual Behavior
After canceling query (and catching errors in code) gino_startlette stills throws error asyncpg.exceptions.QueryCanceledError when trying to release connection.
Steps to Reproduce the Problem
from asyncpg import QueryCanceledError
from fastapi import FastAPI
from gino_starlette import Gino
app = FastAPI()
db = Gino(
app,
kwargs=dict(server_settings=dict(statement_timeout="1")), # cancel query after 1 ms
)
@app.get("/")
async def root():
message = "success"
try:
await db.scalar("SELECT 1")
except QueryCanceledError:
message = "timeout"
return {"message": message}
When called, Endpoint will correctly return {"message": "timeout"} but app will still throw QueryCanceledError
Traceback (most recent call last):
File "****/site-packages/uvicorn/protocols/http/httptools_impl.py", line 385, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "****/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "****/site-packages/fastapi/applications.py", line 181, in __call__
await super().__call__(scope, receive, send)
File "****/site-packages/starlette/applications.py", line 102, in __call__
await self.middleware_stack(scope, receive, send)
File "****/site-packages/starlette/middleware/errors.py", line 181, in __call__
raise exc from None
File "****/site-packages/starlette/middleware/errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "****/site-packages/gino_starlette.py", line 83, in __call__
await conn.release()
File "****/site-packages/gino/engine.py", line 300, in release
await dbapi_conn.release(True)
File "****/site-packages/gino/engine.py", line 48, in release
return await self._release()
File "****/site-packages/gino/engine.py", line 84, in _release
await self._pool.release(conn)
File "****/site-packages/gino/dialects/asyncpg.py", line 280, in release
await self._pool.release(conn)
File "****/site-packages/asyncpg/pool.py", line 654, in release
return await asyncio.shield(ch.release(timeout))
File "****/site-packages/asyncpg/pool.py", line 216, in release
raise ex
File "****/site-packages/asyncpg/pool.py", line 206, in release
await self._con.reset(timeout=budget)
File "****/site-packages/asyncpg/connection.py", line 1137, in reset
await self.execute(reset_query, timeout=timeout)
File "****/site-packages/asyncpg/connection.py", line 295, in execute
return await self._protocol.query(query, timeout)
File "asyncpg/protocol/protocol.pyx", line 316, in query
asyncpg.exceptions.QueryCanceledError: canceling statement due to statement timeout
Specifications
- Python version: 3.8
- GINO version: 1.0.1
- Starlette version: 0.1.1
Workarounds
I can suppress the error message when replacing this line https://github.com/python-gino/gino-starlette/blob/master/src/gino_starlette.py#L83 with this:
try:
await conn.release()
except QueryCanceledError:
pass
But I am not quite sure if this is the best approach