Skip to content
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

Websockets RuntimeError "This event loop is already running" #1354

Open
savelyevlad opened this issue Aug 20, 2023 · 7 comments
Open

Websockets RuntimeError "This event loop is already running" #1354

savelyevlad opened this issue Aug 20, 2023 · 7 comments

Comments

@savelyevlad
Copy link

When I'm trying to run a websocket, then in some time stop it, and run a new websocket, the following error occurs:

Exception in thread Thread-2:
Traceback (most recent call last):

File "D:\python\Python39\lib\threading.py", line 950, in _bootstrap_inner
self.run()
File "D:\python\Python39\lib\site-packages\binance\threaded_stream.py", line 59, in run
self._loop.run_until_complete(self.socket_listener())
File "D:\python\Python39\lib\asyncio\base_events.py", line 618, in run_until_complete
self._check_running()
File "D:\python\Python39\lib\asyncio\base_events.py", line 578, in _check_running
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
D:\python\Python39\lib\threading.py:952: RuntimeWarning: coroutine 'ThreadedApiManager.socket_listener' was never awaited
self._invoke_excepthook(self)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

This is a part of code which I use to run websocket:
twm = ThreadedWebsocketManager(self.main_window.api_key, self.main_window.api_secret)
twm.start()

current_candle_websocket = twm.start_kline_futures_socket(callback=self.handle_candle_message, symbol=self.symbol, interval=Client.KLINE_INTERVAL_5MINUTE)

This is a part of code which I use to stop websocket:
twm.stop_socket(current_candle_websocket)
twm.stop()
twm = ''

I use Python 3.9. The error didn't occur on python-binance 1.0.15, but since some API features are retired I can no longer use this version and updated python-binance to 1.0.19, and after that I am getting this error.

@alexrmacleod
Copy link

alexrmacleod commented Sep 7, 2023

getting the same error, running in notebook this error only happens on junypter notebook runs fine as a python conda script

can get it working with python-binance 1.0.15 but need to use 1.0.19 for the new futures endpoints
tried on Python 3.9 & Python 3.7 same issue

trying to use 1.0.19 version to get new futures endpoints but getting the below error

Exception in thread Thread-4:
Traceback (most recent call last):
File "/Users/alex/opt/anaconda3/envs/trader/lib/python3.7/threading.py", line 926, in _bootstrap_inner
self.run()
File "/Users/alex/opt/anaconda3/envs/trader/lib/python3.7/site-packages/binance/threaded_stream.py", line 59, in run
self._loop.run_until_complete(self.socket_listener())
File "/Users/alex/opt/anaconda3/envs/trader/lib/python3.7/asyncio/base_events.py", line 563, in run_until_complete
self._check_runnung()
File "/Users/alex/opt/anaconda3/envs/trader/lib/python3.7/asyncio/base_events.py", line 523, in _check_runnung
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running

/Users/alex/opt/anaconda3/envs/trader/lib/python3.7/threading.py:960: RuntimeWarning: coroutine 'ThreadedApiManager.socket_listener' was never awaited
del exc_type, exc_value, exc_tb
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

code:

def start_trading(self, historical_days):
        
        client.futures_change_leverage(symbol = self.symbol, leverage = self.leverage) # NEW
        
        self.twm = ThreadedWebsocketManager(testnet = False) # testnet
        self.twm.start()
        
        if self.bar_length in self.available_intervals:
            self.get_most_recent(symbol = self.symbol, interval = self.bar_length, days = historical_days)
            self.twm.start_kline_futures_socket(callback = self.stream_candles, symbol = self.symbol, interval = self.bar_length) # Adj: start_kline_futures_socket
            self.twm.join() # for script only not notebook

@sammchardy 🙏

@wanglili-dartmouth
Copy link

@sammchardy same here, happened in python 3.7, 3.8, 3.9,3.10.
If changed to python 3.5 or 3.6, another error will occur [Python3.6 AttributeError: module 'asyncio' has no attribute 'run']

@OpenCoderX
Copy link
Contributor

I get the same error, it's block me from upgrading.

@OpenCoderX
Copy link
Contributor

I would pay to have this fixed.

@LoveBloodAndDiamonds
Copy link

LoveBloodAndDiamonds commented Nov 18, 2023

i have same problem, but i fix it.

Problem was in what i create twm instance in Thread-N, and try to use it in Thread-N+1

twm = ThreadedWebsocketManager(self.main_window.api_key, self.main_window.api_secret)

looks like you write some desktop app, so try watch what with threads there

@WonniPooh
Copy link

Please correct me if I am wrong, but as I see from the code - the ThreadedWebsocketManager is inherited from ThreadedApiManager, which is also inherited, from threading.Thread.

So on creation of ThreadedWebsocketManager a constructor of ThreadedApiManager is called, that calls

class ThreadedApiManager(threading.Thread):

    def __init__(
        self, api_key: Optional[str] = None, api_secret: Optional[str] = None,
        requests_params: Optional[Dict[str, Any]] = None, tld: str = 'com',
        testnet: bool = False, session_params: Optional[Dict[str, Any]] = None
    ):
        """Initialise the BinanceSocketManager

        """
        super().__init__()
        self._loop: asyncio.AbstractEventLoop = get_loop()
def get_loop():
    """check if there is an event loop in the current thread, if not create one
    inspired by https://stackoverflow.com/questions/46727787/runtimeerror-there-is-no-current-event-loop-in-thread-in-async-apscheduler
    """
    try:
        loop = asyncio.get_event_loop()
        return loop
    except RuntimeError as e:
        if str(e).startswith("There is no current event loop in thread"):
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            return loop
        else:
            raise

And then when we call ThreadedWebsocketManager.start(), the run() method of ThreadedApiManager is invoked:

    def run(self):
        self._loop.run_until_complete(self.socket_listener())

Before the changes in commit
77266da

a new event loop was created, what was perfectly logical, though get_loop() is called in a ThreadedApiManager constructor, which is called BEFORE starting the ThreadedWebsocketManager thread. So we will get the event_loop of our main thread. And if I am using asyncio - having an event loop in current thread I am creating ThreadedWebsocketManager from, that running loop is returned to be used by that new instance of ThreadedWebsocketManager in a new loop!

And if, in some case, I want to create 2 ThreadedWebsocketManager classes, I will get an error of

Exception in thread Thread-5:
Traceback (most recent call last):
  File "/usr/lib64/python3.12/threading.py", line 1073, in _bootstrap_inner
    self.run()
  File "/home/oserbin/.local/lib/python3.12/site-packages/binance/threaded_stream.py", line 59, in run
    self._loop.run_until_complete(self.socket_listener())
  File "/usr/lib64/python3.12/asyncio/base_events.py", line 660, in run_until_complete
    self._check_running()
  File "/usr/lib64/python3.12/asyncio/base_events.py", line 619, in _check_running
    raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running

And printing event loop object addresses of 2 separate objects of ThreadedWebsocketManager that what I get:
0x7f2e3a90d070
0x7f2e3a90d070

So I may misunderstand something, please correct me if I am wrong and there is no bug in it.

@WonniPooh
Copy link

WonniPooh commented Jan 22, 2024

I would pay to have this fixed.

I don't know what is your situation exactly, but the problem described by me above could be solved by replacing

self._loop: asyncio.AbstractEventLoop = get_loop()
to
self._loop: asyncio.AbstractEventLoop = asyncio.new_event_loop()
in file https://github.com/sammchardy/python-binance/blob/master/binance/threaded_stream.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants
@OpenCoderX @alexrmacleod @WonniPooh @pcriadoperez @savelyevlad @wanglili-dartmouth @LoveBloodAndDiamonds and others