Search code examples
pythondiscorddiscord.pycoroutine

How to cancel a pending wait_for


Assuming a command similar to this:

@bot.command()
async def test(ctx):
    def check(r, u):
        return u == ctx.message.author and r.message.channel == ctx.message.channel and str(r.emoji) == '✅'

    await ctx.send("React to this with ✅")
    try:
        reaction, user = await bot.wait_for('reaction_add', timeout=300.0, check=check)
    except asyncio.TimeoutError:
        await ctx.send('Timeout')
    else:
        await ctx.send('Cool, thanks!')

Is there any way to cancel that wait_for if the user sends the same command multiple times before actually reacting to the message? So the bot stop waiting for reactions on previously sent messages and only waits for the last one.


Solution

  • Would something like this work for you?

    pending_tasks = dict()
    
    async def test(ctx):
        def check(r, u):
            return u == ctx.message.author and r.message.channel == ctx.message.channel and str(r.emoji) == '✅'
    
        await ctx.send("React to this with ✅")
        try:
            if ctx.message.author in pending_tasks:
                pending_tasks[ctx.message.author].close()
            pending_tasks[ctx.message.author] = bot.wait_for('reaction_add', timeout=300.0, check=check)
            reaction, user = await pending_tasks[ctx.message.author]
        except asyncio.TimeoutError:
            await ctx.send('Timeout')
        else:
            await ctx.send('Cool, thanks!')
    

    You store all of the pending requests in a dict, and before creating another request you check if you are already have an existing task for this user, if you do you cancel it and create a new one

    Edit: 16/05/23 when you are done with the task, you should delete the old task from the dict, otherwise it will grow needlessly