Nicolas Rey
Nicolas Rey

Reputation: 481

Python RuntimeError: This event loop is already running

It is a very common issue, but I cannot actually find a proper answer to it. I have the following code to connect to a server through a websocket and I want to keep it alive and keep listening to messages it sends like below:

import asyncio
import websockets
import nest_asyncio
nest_asyncio.apply()
            
async def listen_for_message(websocket):
    while True:
        await asyncio.sleep(0)
        message = await websocket.recv()
        print(message)

async def connect_to_dealer():
    websocket = await websockets.connect(websocketadress)

    hello_message = await websocket.recv()
    print(hello_message)

async def my_app():
    websocket = await connect_to_dealer()
    asyncio.ensure_future(listen_for_message(websocket))

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(my_app())
    loop.run_forever()

And it raises the error:

  File "\untitled0.py", line 71, in <module>
    loop.run_forever()
  File "\Anaconda3\lib\asyncio\base_events.py", line 525, in run_forever
    raise RuntimeError('This event loop is already running') 
RuntimeError: This event loop is already running

And without the

import nest_asyncio
nest_asyncio.apply()

I get:

  File "\untitled0.py", line 70, in <module>
    loop.run_until_complete(my_app()) 
  File "\Anaconda3\lib\asyncio\base_events.py", line 570, in run_until_complete
    self.run_forever()
  File "\Anaconda3\lib\asyncio\base_events.py", line 525, in run_forever
    raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running

I still do not understand why it does this.

Upvotes: 3

Views: 18403

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122352

loop.run_until_complete() already runs your loop 'forever'.

Instead of firing of your listen_for_message() awaitable as a task, just await on it. That then runs forever, because listen_for_message() itself never returns:

async def my_app():
    websocket = await connect_to_dealer()
    await listen_for_message(websocket)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(my_app())

Note that your connect_to_dealer() function doesn't return the websocket; that's probably an oversight you want to correct:

async def connect_to_dealer():
    return await websockets.connect(websocketadress)

I removed the hello_message = await websocket.recv() / print(hello_message) lines there because listen_for_message() will already receive messages and print them.

Upvotes: 4

Related Questions