首页 > 解决方案 > How do I correctly use tasks/the event loop in a discord.py bot?

问题描述

I read the answer here and tried to adapt it for my own usage: How to add a function to discord.py event loop?

My situation is as follows:

I'm developing a discord bot in which I have some commands users can run. These commands have a possibility of erroring, in which case I do client.loop.create_task(errorReportingFunction()) which reports the error to me by messaging me. I also have a command which uses asyncio.create_task() instead.

However I'm having memory leaks which vary from mild to crashing the bot after prolonged usage which leads me to think that I'm not using the tasks system correctly. Should I be cleaning up after the tasks I create and deleting them somehow after I'm done using them? Or is there a system that does that automatically.

I'm also not sure how asyncio.create_task() and client.loop.create_task() differ so I'd appreciate some advice on which to use when, or if they're basically the same.

标签: pythondiscordtaskdiscord.py

解决方案


我相信您想要的是在发生错误时做某事(例如发送消息)。如果是这样,在 discord.py 中有更好的方法来处理这个问题,而不是创建任务。

如果您只想为某个函数控制它,您可以创建一个错误处理程序来跟踪从该函数引发的错误,并在发生错误时向您发送一条消息:

@bot.command()
async def info(ctx, *, member: discord.Member):
    """Tells you some info about the member."""
    fmt = '{0} joined on {0.joined_at} and has {1} roles.'
    await ctx.send(fmt.format(member, len(member.roles)))

@info.error
async def info_error(ctx, error):
    if isinstance(error, commands.BadArgument):
        await ctx.send('I could not find that member...')
    # Send a message to the bot owner about the error
    await self.bot.get_user(self.bot.owner_id).send('There has been an error in the command')

虽然不和谐机器人的常见做法是有一个错误处理 cog,这将允许您将所有错误处理集中在一个函数中。它可能是这样的:

class ErrorCog(commands.Cog, name='Error'):
    '''Cog in charge of the error handling functions.'''

    def __init__(self, bot):
        self.bot = bot

    @commands.Cog.listener()
    async def on_command_error(self, ctx, error):
        '''Event that takes place when there is an error in a command.
    
        Keyword arguments:
        error -- error message '''

        error = getattr(error, 'original', error)
        
        # Wrong command
        if isinstance(error, commands.CommandNotFound):
            message = 'This is not a valid command'
            return await ctx.send(message)

        # Command is on cooldown
        elif isinstance(error, commands.CommandOnCooldown):
            if ctx.author.id is self.bot.owner_id:
                ctx.command.reset_cooldown(ctx)
                return await ctx.command.reinvoke(ctx)
            cooldowns = {
                commands.BucketType.default: f'for the whole bot.',
                commands.BucketType.user: f'for you.',
                commands.BucketType.guild: f'for this server.',
                commands.BucketType.channel: f'for this channel.',
                commands.BucketType.member: f'cooldown for you.',
                commands.BucketType.category: f'for this channel category.',
                commands.BucketType.role: f'for your role.'
            }
            return await ctx.send(f'The command `{ctx.command}` is on cooldown {cooldowns[error.cooldown.type]} ')
        
        # Bot lacks permissions.
        elif isinstance(error, commands.BotMissingPermissions):
            permissions = '\n'.join([f'> {permission}' for permission in error.missing_perms])
            message = f'I am missing the following permissions required to run the command `{ctx.command}`.\n{permissions}'
            try:
                return await ctx.send(message)
            except discord.Forbidden:
                try:
                    return await ctx.author.send(message)
                except discord.Forbidden:
                    return

        # Here you need to add more instances
        # of errors according to your needs

def setup(bot):
    bot.add_cog(ErrorCog(bot))

推荐阅读