-
-
Notifications
You must be signed in to change notification settings - Fork 153
Description
self._ib_client.sleep(2)
~~~~~~~~~~~~~~~~~~~~~^^^
File "/lib/python3.13/site-packages/ib_async/util.py", line 405, in sleep
run(asyncio.sleep(secs))
~~~^^^^^^^^^^^^^^^^^^^^^
File "/lib/python3.13/site-packages/ib_async/util.py", line 360, in run
result = loop.run_until_complete(task)
File "/usr/lib64/python3.13/asyncio/base_events.py", line 696, in run_until_complete
self._check_running()
~~~~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.13/asyncio/base_events.py", line 632, in _check_running
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
Disclaimer: Perhaps it is my fault for using the builtin sleep function - maybe I did that a long time ago when I was first learning ib_async and asyncio in general. Perhaps, it is not intended to be used in async contexts, or when trying to use ib_async to manage the event loop.
On with the proposed description - but again, perhaps I am wrong here so take it with a grain of salt:
This library should not use a loop to run asyncio.sleep(). That's because you can cause an event loop error that's difficult to determine the root cause for in large async environments where many components are using the same event loop.
I actually think the problem is in util.py line 484
def getLoop():
"""Get the asyncio event loop for the current thread."""
return asyncio.get_event_loop_policy().get_event_loop()
gpt analysis:
Given the function's intended behavior, it should return the existing running event loop if one is active. However, the error indicates that the code is attempting to run the event loop again while it's already active. Here's why this might be happening:
- Mixing Synchronous and Asynchronous Code
Your run function in ib_async/util.py is designed to handle both synchronous and asynchronous contexts. Here's the problematic part:
> def run(*awaitables: Awaitable, timeout: Optional[float] = None):
> loop = getLoop()
> # ...
> result = loop.run_until_complete(task)
> # ...
When run is called from within an asynchronous context (i.e., when the event loop is already running), loop.run_until_complete(task) attempts to start the event loop again, leading to the RuntimeError.
- The sleep Function's Implementation
The sleep function is defined as a synchronous function that internally calls run(asyncio.sleep(secs)):
> def sleep(secs: float = 0.02) -> bool:
> run(asyncio.sleep(secs))
> return True
When sleep is invoked within an asynchronous function (which is likely the case in your stack trace), it triggers the run function to attempt to start the event loop again, causing the error.