How to make discord.py bot run forever if client.run() returns
问题
我的discord.py bot的client.run()每隔几天就意外返回一次,随后出现一个错误"任务已被破坏,但仍处于挂起状态!".
问题
为什么client.run()会返回?我怎样才能改变我的机器人程序来正确处理这个问题并永远运行?
代码(为了便于讨论,去掉了很多代码):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import asyncio import discord TOKEN = 'my bot token goes here' CHANNEL_ID = 'my channel id goes here' async def DiscordMsgSendTask(): await client.wait_until_ready() my_channel = discord.Object(id=CHANNEL_ID) while not client.is_closed: # wait a bit to prevent busy loop await asyncio.sleep(2) # check for and handle new event here # if an event was handled then send a message to the channel embed = discord.Embed(description='Event was handled') await client.send_message(my_channel, embed=embed) client = discord.Client() while True: client.loop.create_task(DiscordMsgSendTask()) try: client.run(TOKEN) except Exception as e: logging.warning('Exception: ' + str(e)) client = discord.Client() |
附加信息
bot的目的基本上只是检查特定目录中的新文件,然后将消息发送到特定的discord通道来报告它。这种情况一天只发生10次,所以机器人的流量非常低。
为了让bot能够容忍错误/断开连接,我将它放入while-true循环,这可能是错误的方法。
使用python 3.6.5和discord.py 0.16.12
编辑-添加的回溯
添加当天早些时候以前失败的回溯。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 2018-06-20 04:33:08 [ERROR] Task exception was never retrieved future: <Task finished coro=<WebSocketCommonProtocol.run() done, defined at /usr/local/lib64/python3.6/site-packages/websockets/protocol.py:428> exception=ConnectionResetError(104, 'Connection reset by peer')> Traceback (most recent call last): File"/usr/local/lib64/python3.6/site-packages/websockets/protocol.py", line 434, in run msg = yield from self.read_message() File"/usr/local/lib64/python3.6/site-packages/websockets/protocol.py", line 456, in read_message frame = yield from self.read_data_frame(max_size=self.max_size) File"/usr/local/lib64/python3.6/site-packages/websockets/protocol.py", line 511, in read_data_frame frame = yield from self.read_frame(max_size) File"/usr/local/lib64/python3.6/site-packages/websockets/protocol.py", line 546, in read_frame self.reader.readexactly, is_masked, max_size=max_size) File"/usr/local/lib64/python3.6/site-packages/websockets/framing.py", line 86, in read_frame data = yield from reader(2) File"/usr/lib64/python3.6/asyncio/streams.py", line 674, in readexactly yield from self._wait_for_data('readexactly') File"/usr/lib64/python3.6/asyncio/streams.py", line 464, in _wait_for_data yield from self._waiter File"/usr/lib64/python3.6/asyncio/selector_events.py", line 723, in _read_ready data = self._sock.recv(self.max_size) ConnectionResetError: [Errno 104] Connection reset by peer 2018-06-20 04:33:08 [ERROR] Task was destroyed but it is pending! task: <Task pending coro=<DiscordMsgSendTask() running at /home/bot.py:119> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7fc99bfd7a68>()]>> 2018-06-20 04:33:08 [ERROR] Unclosed client session client_session: |
号
不能使用预定义的
以下示例将在bot收到消息"die"时引发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | import asyncio import discord TOKEN = 'TOKEN_HERE' client = discord.Client() async def task(): await client.wait_until_ready() while True: await asyncio.sleep(1) print('Running') def handle_exit(): print("Handling") client.loop.run_until_complete(client.logout()) for t in asyncio.Task.all_tasks(loop=client.loop): if t.done(): t.exception() continue t.cancel() try: client.loop.run_until_complete(asyncio.wait_for(t, 5, loop=client.loop)) t.exception() except asyncio.InvalidStateError: pass except asyncio.TimeoutError: pass except asyncio.CancelledError: pass while True: @client.event async def on_message(m): if m.content == 'die': print("Terminating") raise SystemExit client.loop.create_task(task()) try: client.loop.run_until_complete(client.start(TOKEN)) except SystemExit: handle_exit() except KeyboardInterrupt: handle_exit() client.loop.close() print("Program ended") break print("Bot restarting") client = discord.Client(loop=client.loop) |
不协调(某人键入
1 | die |
号
输入终端(stdout):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Running Running Running Terminating Handling Bot restarting Running Running Running Running Running <CTRL-C> (KeyboardInterrupt) Handling Program ended |
旁注:
如果你仍然对你的错误感到困惑,那不是你的错。errno 104是一个服务器端的致命错误,最终用户通常无法预防。