RuntimeError: Task got Future <Future pending> attached to a different loop
Asked Answered
K

3

13

How to call async method which get event loop in main thread inside another async method in Quart?

t.py

from telethon import TelegramClient, functions, types

client2 = TelegramClient(sn, api_id, api_hash).start()

async def create_contact():
    return await client2(functions.contacts.ImportContactsRequest([
        types.InputPhoneContact(0, '8', 'first_name', 'last_name')
    ]))

app.py

from quart import Quart, websocket,render_template,request
import t2
app = Quart(__name__)

@app.route('/wa2tg')
def wa2tg():
    return render_template('wa2tg.html',nm=request.args.get('nm',''))

@app.websocket('/wa2tg2')
async def wa2tg2():
    while True:
        data = await websocket.receive()
        await t2.create_contact()

# Thread(target=tele.client2.run_until_disconnected).start()
app.run(debug=1)        

Error:

Running on http://127.0.0.1:5000 (CTRL + C to quit)
[2019-06-21 16:31:42,035] 127.0.0.1:51696 GET /wa2tg 1.1 200 553 12995
[2019-06-21 16:31:42,486] 127.0.0.1:51698 GET /wa2tg2 1.1 101 - 999
[2019-06-21 16:31:42,490] ERROR in app: Exception on websocket /wa2tg2
Traceback (most recent call last):
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 1629, in handle_websocket
    return await self.full_dispatch_websocket(websocket_context)
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 1651, in full_dispatch_websocket
    result = await self.handle_user_exception(error)
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 948, in handle_user_exception
    raise error
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 1649, in full_dispatch_websocket
    result = await self.dispatch_websocket(websocket_context)
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\app.py", line 1694, in dispatch_websocket
    return await handler(**websocket_.view_args)
  File "D:\SmartBot\my_env\SmartBot\t.py", line 13, in wa2tg2
    await t2.create_contact()
  File "D:\SmartBot\my_env\SmartBot\t2.py", line 22, in create_contact
    types.InputPhoneContact(0, '8807328487', 'first_name', 'last_name')
  File "C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\telethon\client\users.py", line 60, in __call__
    result = await future
RuntimeError: Task <Task pending coro=<ASGIWebsocketConnection.handle_websocket() running at C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\site-packages\quart\asgi.py:135> cb=[_wait.<locals>._on_completion() at C:\Users\Smart\AppData\Local\Programs\Python\Python37-32\lib\asyncio\tasks.py:440]> got Future <Future pending> attached to a different loop

How to pass event loop to quart? I tried to get the loop and set inside function but still got error

loop = asyncio.get_event_loop()
@app.websocket('/wa2tg2')
async def wa2tg2():
  while True:
    asyncio.set_event_loop(loop)
    data = await websocket.receive()
    await t2.create_contact()
Kennithkennon answered 20/6, 2019 at 15:21 Comment(1)
By editing your question to change your code after receiving answers, you make it much less useful to people with similar problems who find this question when looking for help.Literatim
K
0

Solved after passing loop to app.run

loop = asyncio.get_event_loop()
app.run(debug=1,loop=loop)        

Thread for client.run_until_disconnected() not needed since we pass the loop to the run method

More on Telethon and Quart

Kennithkennon answered 21/6, 2019 at 13:40 Comment(0)
R
3

When you do:

TelegramClient(sn, api_id, api_hash)

Telethon needs to asyncio.get_event_loop(). This method returns the event loop for the current thread, which in your code, is the main thread. Telethon then remembers and uses the loop from the main thread.

When you do:

Thread(target=tele.client2.run_until_disconnected).start()

You are creating a new thread, and you get the corresponding error "Task got Future attached to a different loop" for the reasons I have explained.

When using asyncio, you generally shouldn't use threading unless you really know what you're doing.

In fact, the code can be rewritten as (removing all the unnecessary imports which probably were added without much thought):

Tele.py

from telethon import TelegramClient, functions, types

client = TelegramClient(sn, api_id, api_hash).start()

async def create_contact():
    return await client2(functions.contacts.ImportContactsRequest([
        types.InputPhoneContact(0, phone_number, first_name, last_name)
    ]))

app.py

from quart import Quart, websocket

app = Quart(__name__)

@app.websocket('/wa2tg2')
async def wa2tg2():
    while True:
        data = await websocket.receive()
        await tele.create_contact()

Some things to note:

  • client.start() can work without await.
  • client.run_until_disconnected() only needs to be called if you need to.
  • async def are called by using await on them, not by creating a separate thread.
  • The 0 you use in input contact will only work once (or not at all), since it needs to be a random number.
  • Never copy paste blindly. Understand what it does first.
Ruffled answered 21/6, 2019 at 9:53 Comment(3)
Error raised in function only. Threading works fine. But I commented out threading and still the same errorKennithkennon
The 0 you use in input contact will only work once (or not at all), since it needs to be a random number. works fineKennithkennon
Official applications use random numbers, and we have had issues with it in the past.Ruffled
K
0

Solved after passing loop to app.run

loop = asyncio.get_event_loop()
app.run(debug=1,loop=loop)        

Thread for client.run_until_disconnected() not needed since we pass the loop to the run method

More on Telethon and Quart

Kennithkennon answered 21/6, 2019 at 13:40 Comment(0)
A
0

It actually happens because Uvicorn tends to instantiate its own event loop.

In a nutshell, put your FastAPI app instantiation and the Uvicorn invocation in two separate files. This will resolve the issue.

Aerodrome answered 6/2, 2023 at 19:54 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Allodium

© 2022 - 2024 — McMap. All rights reserved.