在一个文件中运行两个事件循环
我创建了一个网页应用,这个应用有两个事件循环。一个是用Quart这个小框架做的网页应用的事件循环,另一个是用来处理Discord机器人的。
因为我需要同时运行两个事件循环,所以我为Discord机器人开了一个线程。
当我用Python解释器运行这个应用时,一切都正常,但当我用Uvicorn来运行Quart应用时,就出现问题了。
# Application.py
import os
import sys
import quart
from quart_discord import DiscordOAuth2Session
from Database import InformationLogManager
from Bot import Main
import threading
import asyncio
import typelog
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
GUILD_ID = 1208428835960520734
ROLE_ID = 1208433206215315558
Application = quart.Quart('888KingBotDashboard')
InformationLogManager = InformationLogManager.InformationLogManager() # this is a database
Logger = typelog.get_logger(__name__)
Application.config["SECRET_KEY"] = "thebigchickens"
Application.config["DISCORD_CLIENT_ID"] = '1208431980954525746'
Application.config["DISCORD_CLIENT_SECRET"] = 'ghvM9A2128vrz9vEzXrvOxp1ff28FIEC'
Application.config["DISCORD_REDIRECT_URI"] = "http://localhost:8080/callback"
DiscordOAuth2Session = DiscordOAuth2Session(Application)
@Application.before_serving
async def BeforeFirstRequest():
BotThread = threading.Thread(target=Main.RunBot) # Runs the Discord bot.
BotThread.start()
@Application.route('/')
async def index():
return await quart.render_template('index.html')
@Application.route('/login')
async def Login():
return await DiscordOAuth2Session.create_session()
@Application.route('/callback')
async def callback():
try:
await DiscordOAuth2Session.callback()
except Exception:
return quart.redirect(quart.url_for("login"))
User = await DiscordOAuth2Session.fetch_user()
print(User)
return await quart.render_template('logged_in_success.html', User = User)
@Application.route('/dashboard')
async def dashboard():
for Guild in await DiscordOAuth2Session.fetch_guilds():
if Guild.id == GUILD_ID:
User = await DiscordOAuth2Session.fetch_user()
if await Main.CheckForRole(GuildId = GUILD_ID, RoleId = ROLE_ID, UserId = User.id):
InformationLogManager.LogInformation(
DiscordUserId = User.id,
IPAddress = quart.request.remote_addr,
Email = User.email
)
return await quart.render_template("dashboard.html", User = User)
else:
break
else:
continue
return await quart.render_template("access_denied.html"), 401
Exception in thread Thread-1 (RunBot):
Traceback (most recent call last):
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\disnake\client.py", line 1116, in run
Exception in callback Future.set_result(True)
handle: <TimerHandle when=527018.265 Future.set_result(True)>
Traceback (most recent call last):
File "C:\Users\junej\AppData\Local\Programs\Python\Python310\lib\asyncio\events.py", line 80, in _run
self._context.run(self._callback, *self._args)
asyncio.exceptions.InvalidStateError: invalid state
loop.run_forever()
File "C:\Users\junej\AppData\Local\Programs\Python\Python310\lib\asyncio\windows_events.py", line 319, in run_forever
INFO: ASGI 'lifespan' protocol appears unsupported.
assert self._self_reading_future is None
AssertionError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\disnake\client.py", line 133, in _cleanup_loop
_cancel_tasks(loop)
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\disnake\client.py", line 115, in _cancel_tasks
loop.run_until_complete(asyncio.gather(*tasks, return_exceptions=True))
File "C:\Users\junej\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 617, in run_until_complete
self._check_running()
File "C:\Users\junej\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 577, in _check_running
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\uvicorn\server.py", line 79, in serve
await self.startup(sockets=sockets)
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\uvicorn\server.py", line 161, in startup
server = await loop.create_server(
File "C:\Users\junej\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 1459, in create_server
infos = await tasks.gather(*fs)
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\junej\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Users\junej\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "C:\Users\junej\dev\888BotRestructure\venv\Scripts\uvicorn.exe\__main__.py", line 7, in <module>
sys.exit(main())
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\click\core.py", line 1157, in __call__
return self.main(*args, **kwargs)
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\click\core.py", line 1078, in main
rv = self.invoke(ctx)
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\click\core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\click\core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\uvicorn\main.py", line 418, in main
run(
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\uvicorn\main.py", line 587, in run
server.run()
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\uvicorn\server.py", line 62, in run
Client.run("MTIwODQzMTk4MDk1NDUyNTc0Ng.GJL1Ys.WJk760ouaguhQ818OJMu8z9GvKDOzFAA0pBxuk")
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\disnake\client.py", line 1122, in run
_cleanup_loop(loop)
File "C:\Users\junej\dev\888BotRestructure\venv\lib\site-packages\disnake\client.py", line 137, in _cleanup_loop
loop.close()
File "C:\Users\junej\AppData\Local\Programs\Python\Python310\lib\asyncio\proactor_events.py", line 676, in close
raise RuntimeError("Cannot close a running event loop")
RuntimeError: Cannot close a running event loop
1 个回答
0
更新,我解决了这个问题。
基本上,我做的就是使用 asyncio.get_event_loop
,来获取当前由 Uvicorn 服务器创建的事件循环。这个方法返回了一个 ProactorEventLoop
对象,然后我用它的 create_task
方法来运行我的机器人。
这是我做的更新:
ApplicationEventLoop: asyncio.windows_events.ProactorEventLoop = asyncio.get_event_loop()
ApplicationEventLoop.create_task(Main.RunBot())