Home > database >  Discord Bot Asynchronous Loop Failure
Discord Bot Asynchronous Loop Failure

Time:08-29

Please be patient with me. I'm actually not a coder and working with code that was left to us by someone who we can no longer contact and get help with. I've tried to do some research on my own, but I unfortunately can't extrapolate from other solutions to ours due to my insufficient skills.

Part of the issue is also that our code is probably less than optimal and could be looped better by assigning i-values to each task, but I unfortunately don't know how to change it, so I'm just trying to find a solution with what we have. It was working on Heroku, but with their upcoming removal of their free services, we're looking to import it elsewhere and running into errors.

Briefly, we have a very simple Discord bot whose purpose is to check certain channels and send a message when those channels have not had activity within a certain time period. In more detail, here is the general code for checking one of the channels:

import discord
import datetime
import asyncio
import math
from discord.ext import tasks

client = discord.Client(intents=discord.Intents.default())

@client.event
async def on_ready():
    print('Ready'.format(client))

@tasks.loop(seconds = 30)
async def channelname():
    await client.wait_until_ready()
    channel_id = ################
    
    channel = client.get_channel(channel_id)
    message = await channel.fetch_message(channel.last_message_id)
    printchannel = client.get_channel(################)
    
    if "message to turn off bot" in message.content.lower():
        return
    else:
        msg_secs = (datetime.datetime.utcnow() - message.created_at).total_seconds()
        if msg_secs >=300  and msg_secs <= 360:
            await printchannel.send('reminder message')
        else:
            return

channelname.start()

client.run('bot token')

When we try to run this code, we are currently running into this error (on Railway):

Traceback (most recent call last):
File "botname.py", line 5610, in <module>
test.start()
File "/opt/venv/lib/python3.8/site-packages/discord/ext/tasks/__init__.py", line 398, in start
self._task = asyncio.create_task(self._loop(*args, **kwargs))
File "/nix/store/bhny2arkxrifw0afjbnqqi0ilqnwndqr-setup-env/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

From what I can tell from looking up this error, the problem is that the loop was just created and cannot have tasks attached to it, so I need to have the code add the tasks in by itself. Unfortunately, all of the solutions I'm finding do use i-values, which we don't use, so I can't figure out how to make it work for us.

Thank you very much in advance for any assistance!

EDITED: Part of code that possibly has other syntax errors. It is intended to check the second-to-last message in a channel for a "certain message" and to print "a warning" if that string is present.

    elif "certain message" in message.content.lower():
        messages = await channel.history(limit=2).flatten()
        second_message = await channel.fetch_message(messages[1].id)
        msg_secs = (datetime.datetime.now().timestamp() - second_message.created_at.timestamp())
        if msg_secs >= 300 and msg_secs <= 360:
            await printchannel.send('a warning')
        else:
            return
    ```

CodePudding user response:

To start a task you need a running event loop.

If you want to use run(), you can start the task in setup_hook where all your async setup should be unless it is cog specific in which case you can put them in cog_load:

from typing import Any

class MyClient(discord.Client):

    def __init__(self, *, intents: discord.Intents, **options: Any) -> None:
        super().__init__(intents=intents, **options)

    async def setup_hook(self) -> None:
        channelname.start()

client = MyClient(intents=discord.Intents.default())

client.run('bot token')

or:

import asyncio

async def main():
    async with client:
        channelname.start()
        await client.start('bot token')

asyncio.run(main())

Also, in your task you are operating on two offset-aware and naive datetime objects which is not allowed, you are probably getting an error but since you don't have an error handler setup it's getting eaten by it.

Do this instead:

msg_secs = (datetime.datetime.now().timestamp() - message.created_at.timestamp())

Instead of flatten(), use this, if you are on 2.0:

messages = [message async for message in channel.history(limit=2)]
  • Related