tortoise / tortoise/tortoise-orm
Unable to perform any orm related stuff from a websocket connection
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 516
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 9
Description
Describe the bug
Whenever I try to connect to a websocket connection from pytest, and I try to run some queries in the database, it crashes and returns the following error
Traceback:
apps/users/selectors.py:7: in get_user
return await User.get_or_none(**kwargs)
/usr/local/lib/python3.8/site-packages/tortoise/queryset.py:885: in _execute
instance_list = await self._db.executor_class(
/usr/local/lib/python3.8/site-packages/tortoise/backends/base/executor.py:124: in execute_select
_, raw_results = await self.db.execute_query(query.get_sql())
/usr/local/lib/python3.8/site-packages/tortoise/backends/asyncpg/client.py:36: in translate_exceptions_
return await func(self, *args)
/usr/local/lib/python3.8/site-packages/tortoise/backends/asyncpg/client.py:186: in execute_query
return len(rows), rows
/usr/local/lib/python3.8/site-packages/tortoise/backends/base/client.py:308: in __aexit__
await self.pool.release(self.connection)
/usr/local/lib/python3.8/site-packages/asyncpg/pool.py:666: in release
return await asyncio.shield(ch.release(timeout))
/usr/local/lib/python3.8/site-packages/asyncpg/pool.py:218: in release
raise ex
/usr/local/lib/python3.8/site-packages/asyncpg/pool.py:208: in release
await self._con.reset(timeout=budget)
/usr/local/lib/python3.8/site-packages/asyncpg/connection.py:1311: in reset
await self.execute(reset_query, timeout=timeout)
/usr/local/lib/python3.8/site-packages/asyncpg/connection.py:297: in execute
return await self._protocol.query(query, timeout)
asyncpg/protocol/protocol.pyx:323: in query
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress
See my code below:
async def is_authenticated(token: str = Security(oauth2_scheme)) -> Union[User, Exception]:
""" Verifies access token, returns user if it is valid (authenticated) else throws an error"""
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[ALGORITHM])
if payload['token_type'] != "access":
raise CustomHTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="Could not validate credentials - Wrong token type)")
token_data = TokenData(**payload)
except jwt.JWTError:
raise CustomHTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="Could not validate credentials - Invalid signature of access token")
user = await get_user(id=token_data.user_id) **# Error is thrown right here**
if not user:
raise CustomHTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="User not found")
return user
async def is_authenticated_ws(websocket: WebSocket,
token: str = Query("")):
# Websocket specific authentication
try:
return await is_authenticated(token)
except:
await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
@websocket_app.websocket("/")
async def websocket_endpoint(websocket: WebSocket,
current_user: User = Depends(is_authenticated_ws)):
if not current_user:
return
service = await accept_user_connection(user_id=current_user.id, websocket=websocket)
await run_until_first_complete(
(producer_handler, {"service": service}),
(consumer_handler, {"service": service, "current_user": current_user})
)
class TestWebSockets:
@pytest.mark.asyncio
async def test_websocket_events(self, ws_client, actor_user):
token = create_token(actor_user.id, generate_verification_code())
with ws_client.websocket_connect(f"/ws/?token={token['access_token']}") as websocket:
...
Obviously it has to do something with the event loop. It is a huge but since in a production environment I should be able to test websocket events without any issues but right now I cant even query something from the database before I connect to a websocket.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with apps/users/selectors.py and TestWebSockets.test_websocket_events, then follow the asyncpg traceback through tortoise/backends/asyncpg/client.py and the connection release path. Reproduce the websocket test and inspect how the event loop and database connection are used around is_authenticated_ws. Done means the websocket test can query the database without asyncpg.InterfaceError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- postgresql, python
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100