つれづれなるままに日々の色々なことを綴ります

【Discord.py】RuntimeError: no running event loopというエラーが出て、tasks.loopが実行できない

はじめに

制作しているDiscord Botの改修作業を行っている途中で、loop周りのエラーにぶち当たりました。解決に少々時間を要したので、メモを残しておきます。

開発環境

  • discord.py 2.1.0
  • python3 3.8.10

起きたこと

Discord Botを実行すると以下のエラー文が出るようになった。

Traceback (most recent call last):
  File "main.py", line 50, in <module>
    loop.start()
  File "/home/oimo/.local/lib/python3.8/site-packages/discord/ext/tasks/__init__.py", line 398, in start
    self._task = asyncio.create_task(self._loop(*args, **kwargs))
  File "/usr/lib/python3.8/asyncio/tasks.py", line 381, in create_task
    loop = events.get_running_loop()
RuntimeError: no running event loop
sys:1: RuntimeWarning: coroutine 'Loop._loop' was never awaited

解決策

  • loopの起動をon_readyの中に仕込む
import discord
from discord.ext import tasks

# この中にloop.startを仕込む
@client.event
async def on_ready():
    loop.start()

@tasks.loop(seconds=60)
async def loop():
    now = datetime.now(timezone('Asia/Tokyo')).strftime('%H:%M')
    if now.hour == 19 and now.minute == 30:
        channel = client.get_channel(CHANNEL_ID)
        await channel.send('ゴミ出しに行こうね!')  

一体なんだったのか

Discord.py 2.0.0/python 3.1以上の環境で、「discord.ext.tasks」を使用しているときに起きるようです。

もともと「discord.ext.tasks」を使うと、asyncioという並行処理のコードを書くためのライブラリを使用せずとも、ループを実行させられるらしい。しかし、Discord.py側のアップデートか何なのかbotの起動前に、ただ単にループ処理実行を書くだけでは上手く起動しないようになっています。

そこで、上記のようにon_readyにループ実行を入れてあげれば動くらしい。

# うまく動作しないパターン
@client.event
async def on_ready():

@tasks.loop(seconds=60)
async def loop():
    now = datetime.now(timezone('Asia/Tokyo')).strftime('%H:%M')
    if now.hour == 19 and now.minute == 30:
        channel = client.get_channel(CHANNEL_ID)
        await channel.send('ゴミ出しに行こうね!')  

loop.start()

まとめ

timezone周りを修正したかっただけなのに、これが出てきてえらい大変困りました。

参考文献

teratail.com