RuntimeError: Timeout context manager should be used inside a task

◇◆丶佛笑我妖孽 提交于 2020-05-29 03:19:05

问题


Background: I am hosting a flask server alongside a discord client

The flask server just needs to pass on messages from the client to discord and from messages from discord to the client.

I am getting the error when I call loop.run_until_complete(sendMsg(request)) I have tried wait_for in sendMsg and wait_for loop.run_until_complete()

I have looked everywhere and haven't found anything so any help would be appreciated.

Code:

import discord
import json
import os
import asyncio
from flask import Flask, request, render_template
from async_timeout import timeout
from threading import Thread
from time import sleep

client = discord.Client()
messages = []
app = Flask(__name__)

def startClient():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    client.run('token')


#
# Discord Events
#
@client.event
async def on_ready():
    print('Discord Client Ready')

@client.event
async def on_message(message):
    global messages
    message.append(message)


#
# Flask Stuff
#
async def sendMsg(request):
    await client.send_message(discord.Object('channel id'), request.form['message'])


@app.route("/chat/", methods=['GET', 'POST'])
def chatPage():
    global messages

    if request.method == 'GET':
        return render_template('main.html')

    elif request.method == 'POST':
        loop = asyncio.new_event_loop()
        loop.run_until_complete(sendMsg(request))
        return ''

@app.route("/chat/get", methods=['GET'])
def chatGet():
    return json.dumps(messages[int(request.args['lastMessageId']):])


# Start everything
os.environ["WERKZEUG_RUN_MAIN"] = 'true'
print('Starting discord.py client')
Thread(target=startClient).start()
print('Starting flask')
app.run(host='0.0.0.0', debug=True)

Traceback:

Traceback (most recent call last):
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 2295, in wsgi_app
    response = self.handle_exception(e)
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1741, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/mnt/c/Users/SuperKooks/Documents/Coding/HTML/kindle-discord/app.py", line 51, in chatPage
    loop.run_until_complete(sendMsg(request))
  File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
    return future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
    result = coro.send(None)
  File "/mnt/c/Users/SuperKooks/Documents/Coding/HTML/kindle-discord/app.py", line 39, in sendMsg
    await client.send_message(discord.Object('382416348007104513'), request.form['message'])
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/discord/client.py", line 1152, in send_message
    data = yield from self.http.send_message(channel_id, content, guild_id=guild_id, tts=tts, embed=embed)
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/discord/http.py", line 137, in request
    r = yield from self.session.request(method, url, **kwargs)
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/aiohttp/client.py", line 555, in __iter__
    resp = yield from self._coro
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/aiohttp/client.py", line 197, in _request
    with Timeout(timeout, loop=self._loop):
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/async_timeout/__init__.py", line 39, in __enter__
    return self._do_enter()
  File "/home/SuperKooks/.local/lib/python3.5/site-packages/async_timeout/__init__.py", line 76, in _do_enter
    raise RuntimeError('Timeout context manager should be used '
RuntimeError: Timeout context manager should be used inside a task

回答1:


The problem looks like it could be caused by the following:

elif request.method == 'POST':
    loop = asyncio.new_event_loop()
    loop.run_until_complete(sendMsg(request))

That creates a new event loop and runs sendMsg(request) in the new loop. However, sendMsg calls a method on the client object running in its own event loop. sendMsg should be submitted to the existing event loop that runs the client in the other thread. To accomplish that, you need to:

  • expose the loop created in startClient, e.g. to a client_loop global variable;
  • replace loop = asyncio.new_event_loop(); loop.run_until_complete(sendMsg(request)) with a call to asyncio.run_coroutine_threadsafe to submit the coroutine to an event loop already running in a different thread.

The submit code would look like this:

elif request.method == 'POST':
    # submit the coroutine to the event loop thread
    send_fut = asyncio.run_coroutine_threadsafe(sendMsg(request), client_loop)
    # wait for the coroutine to finish
    send_fut.result()



回答2:


aiohttp.ClientSession() wants to be called inside a coroutine. Try moving your Client() initializer into any async def function



来源:https://stackoverflow.com/questions/52232177/runtimeerror-timeout-context-manager-should-be-used-inside-a-task

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!