Search code examples
pythonasynchronousdiscorddiscord.pyterminate

How to terminate an async function in discord.py from another command


I'm using discord.ext.commands to make a discord bot. I made a command that constantly keeps unbanning people even if someone is banned. This is the code:

@client.command(name="unban")
async def unban(ctx):
  while True:
    bans = await ctx.guild.bans()
    if(len(bans)>0):
      for ban in bans:
        ctx.guild.unban(ban)
    await asyncio.sleep(5)

But this is a while loop so I want to terminate this function through another command (say, stop_unban). So I want to know how to terminate the unban function through another function (associated with the stop_unban command).


Solution

  • A simple way would be to use a global bool variable that both functions can access to control the banning state.
    For example:

    ban_state = False
    @client.command(name="unban")
    async def unban(ctx):
      global ban_state
      ban_state = True
      while ban_state:
        bans = await ctx.guild.bans()
        if(len(bans)>0):
          for ban in bans:
            await ctx.guild.unban(ban.user)
        await asyncio.sleep(5)
    @client.command(name="stop_unban")
    async def stop_unban(ctx):
      global ban_state
      ban_state = False
      await ctx.send('Unban Mode stopped')
    

    However, another potentially nicer solution if you want the unban mode to last for long periods as well as not using global variables could be to use a background task instead of the while True. For example:

    from discord.ext import tasks
    @tasks.loop(seconds=5.0)
    async def unbanning(ctx):
        bans = await ctx.guild.bans()
        if(len(bans)>0):
          for ban in bans:
            await ctx.guild.unban(ban.user) #btw you need to await this and you have provide the user attribute of the ban not just the ban itself
        
    @client.command(name="unban")
    async def unban(ctx):
      unbanning.start(ctx)
    @client.command(name="stop_unban")
    async def stop_unban(ctx):
      unbanning.cancel()
    

    Here is more info on background tasks :)