-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug: SurrealDB destroys Python Async runtime #138
Comments
@dartt0n |
Destroying the running event loop in a library's code is an unacceptable and unpredictable side effect. This effect will result in closing the asyncio event loop, making any interaction with it (spawning new coroutines, awaiting old ones, etc) throw an exception. There is code to understand how dangerous this is. import asyncio
async def long_running_transaction():
try:
print("starting long running transaction")
await asyncio.sleep(10)
except asyncio.CancelledError:
print("long running transaction cancelled, executing rollback")
await asyncio.sleep(1)
print("rollback done")
else:
print("long running transaction finished, executing commit")
await asyncio.sleep(1)
print("commit done")
finally:
print("long running transaction done, closing connection")
await asyncio.sleep(1)
print("connection closed")
async def dummy_surreal_example():
while True:
try:
await asyncio.sleep(1)
except asyncio.CancelledError:
print("cancelled")
break
asyncio.get_event_loop().stop() # <- the root of all evil, hidden inside library code
async def main():
# spawn several tasks
task1 = asyncio.create_task(long_running_transaction())
task2 = asyncio.create_task(dummy_surreal_example())
await asyncio.sleep(2)
task2.cancel() # cancel the task due to some business logic condition, e.g. timeout
await task2 # wait till graceful shutdown
# start another task, e.g. cleanup job
# however, this task will never be spawned (and executed) since runtime is destroyed by `get_event_loop().stop()`
# you can image this call being in `except` or `finally` block and running some essential transaction logic, e.g. commit or updating customer balance
task3 = asyncio.create_task(long_running_transaction())
await task3
if __name__ == "__main__":
asyncio.run(main()) |
Yup, I get a ton of random errors relating to this all the time:
|
Describe the bug
The library code contains a very (very!) A dangerous call:
surrealdb.py/surrealdb/connection_ws.py
Line 112 in d72ffcc
Whenever surrealdb doesn't receive a websocket update (e.g., a network issue, an invalid address, a serialization error, etc.), it destroys the current async loop (which, in 99.9% of cases, is the main async event loop). This behavior leads to:
This exception and traceback do not contain any information about the reason for failure, nor information about the cause, which is the surrealdb library.
Steps to reproduce
Any websocket failure in any async runtime
Expected behaviour
Graceful failure (raise exception / reconnect / etc)
SurrealDB version
2.1.4
surrealdb.py version
0.4.1
Contact Details
No response
Is there an existing issue for this?
Code of Conduct
The text was updated successfully, but these errors were encountered: