WinError 10038 и, может быть, плохо реализованные таймауты цикла задач? (тоже материал discord.py) Нуб при кодировании здесь
У меня чуть больше 3 недель на то, чтобы научить себя питону, так что терпите меня:')
У меня есть цикл задач, который запускается каждые 5 секунд бесконечно, пока бот работает, бот запускается из фреймворка «RED discord bot», который использует модули, называемые «винтики», над которыми я работал, вот часть моего кода у меня были проблемы с:
# Crosschat loop logic
@tasks.loop(seconds=5)
async def getchat(self):
await self.bot.wait_until_red_ready()
data = await self.config.all_guilds()
for guildID in data:
guild = self.bot.get_guild(int(guildID))
if not guild:
continue
guildsettings = await self.config.guild(guild).clusters()
if not guildsettings:
continue
for cluster in guildsettings:
if not guildsettings[cluster]:
continue
globalchat = guildsettings[cluster]["globalchatchannel"]
for server in guildsettings[cluster]["servers"]:
guildsettings[cluster]["servers"][server]["cluster"] = cluster
guildsettings[cluster]["servers"][server]["globalchat"] = globalchat
if not guildsettings[cluster]["servers"][server]["chatchannel"]:
return
channel = guild.get_channel(int(guildsettings[cluster]["servers"][server]["chatchannel"]))
if not channel:
return
"""Loop using asyncio task loop"""
chattask = []
chattask.append(self.getchatrcon(guild,
guildsettings[cluster]["servers"][server]["cluster"],
guildsettings[cluster]["servers"][server]
))
# Gathers the getchat tasks with a timeout (i think i did it right)
tasks = asyncio.gather(*chattask)
try:
await asyncio.wait_for(tasks, timeout=10)
except asyncio.TimeoutError:
return
# rcon logic for sending a command to the ark servers and returning the message to their designated discord channels.
async def getchatrcon(self, guild, cluster, server):
guildsettings = await self.config.guild(guild).clusters()
adminlogchannel = guild.get_channel(int(guildsettings[cluster]["adminlogchannel"]))
globalchat = guild.get_channel(int(server["globalchat"]))
chatchannel = guild.get_channel(int(server["chatchannel"]))
try:
res = await rcon.asyncio.rcon(
command="getchat",
host=server['ip'],
port=server['port'],
passwd=server['password']
)
if "Server received, But no response!!" in res:
return
msgs = res.split("\n")
filteredmsg = []
for msg in msgs:
if msg.startswith("AdminCmd:"):
adminmsg = msg
await adminlogchannel.send(f"**{server['name'].capitalize()}**\n{box(adminmsg, lang='python')}")
if "): " not in msg:
continue
if "tribe" and ", ID" in msg.lower():
continue # Add more features at a later date for tribe log channels
else:
if msg not in ['', ' ', 'Server received, But no response!! ']:
if not msg.startswith('SERVER:'):
filteredmsg.append(msg)
for msg in filteredmsg:
await globalchat.send(f"{chatchannel.mention}: {msg}")
await chatchannel.send(msg)
except WindowsError as e:
if e.winerror == 121:
return await asyncio.sleep(30)
if e.winerror == 10038:
return await asyncio.sleep(60)
# Just waits till bot is ready to do the loop
@getchat.before_loop
async def before_getchat(self):
print("Getting crosschat loop ready.")
await self.bot.wait_until_red_ready()
Этот код использует команду "getchat" на всех серверах и возвращает сообщения в каналы, которые я установил для указанного сервера, с которого оно пришло. Код действительно работает довольно хорошо в течение первого часа или около того после его запуска, однако я получаю сообщение «WinError 10038», которое через некоторое время начинает рассылать спам в консоли:
[07:28:46] CRITICAL Caught unhandled exception in event loop: [red.main]
Exception in callback _ProactorBasePipeTransport._call_connection_lost(None)
┌───────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────┐
│ C:\Python38\lib\asyncio\events.py:81 in _run │
│ > 81 self._context.run(self._callback, *self._args) │
│ C:\Python38\lib\asyncio\proactor_events.py:162 in _call_connection_lost │
│ > 162 self._sock.shutdown(socket.SHUT_RDWR) │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
OSError: [WinError 10038] An operation was attempted on something that is not a socket
Я заметил, что когда я перезапускаю бота, консоль сотни раз засыпается этой RuntimeError:
RuntimeError: Event loop is closed
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x000002EE9F655E50>
Traceback (most recent call last):
File "C:\Python38\lib\asyncio\proactor_events.py", line 116, in __del__
self.close()
File "C:\Python38\lib\asyncio\proactor_events.py", line 108, in close
self._loop.call_soon(self._call_connection_lost, None)
File "C:\Python38\lib\asyncio\base_events.py", line 719, in call_soon
self._check_closed()
File "C:\Python38\lib\asyncio\base_events.py", line 508, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Моя проблема / проблемы / теории: винтик работает нормально около часа, прежде чем начать спамить WinError, и огромное количество
Мои вопросы:
Может ли ошибка WinError быть вызвана тем, что мой список цикла задач "чат-задачи" переполнен добавленными задачами?
Правильно ли я реализовал тайм-аут, который пытался включить?
Есть ли лучший способ выполнить этот цикл задач?
Операционная система, в которой работает бот, - Windows 10, я также указал в коде следующую политику цикла событий:
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
Я использую эту библиотеку для протокола RCON: https://pypi.org/project/rcon/
Надеюсь, я прояснил, в чем моя проблема, достаточно хорошо, спасибо всем, кто может заметить мне несколько указателей, и всегда ценится немного подержать меня за руку, изучение py было ящиком проб и ошибок для пандоров, но до сих пор супер весело!