Making a discord bot change playing status every 10 seconds

luigiisgreeny picture luigiisgreeny · Sep 17, 2017 · Viewed 25.8k times · Source

I'm trying to make the status for a test discord bot change between two messages every ten seconds. I need the rest of the script to execute while the status message changes, but an error keeps popping up whenever I try to make it work. There's threading in my script, but I'm not entirely sure how to use it in this circumstance.

@test_bot.event
async def on_ready():
    print('Logged in as')
    print(test_bot.user.name)
    print(test_bot.user.id)
    print('------')
    await change_playing()


@test_bot.event
async def change_playing():
    threading.Timer(10, change_playing).start()
    await test_bot.change_presence(game=discord.Game(name='Currently on ' + str(len(test_bot.servers)) +
                                                          ' servers'))
    threading.Timer(10, change_playing).start()
    await test_bot.change_presence(game=discord.Game(name='Say test.help'))

The error message reads:

C:\Python\Python36-32\lib\threading.py:1182: RuntimeWarning: coroutine 'change_playing' was never awaited
  self.function(*self.args, **self.kwargs)

Answer

Sam Rockett picture Sam Rockett · Sep 17, 2017

Threading and asyncio don't play nice together unfortunately. You need to jump through extra hoops to await coroutines inside threads. The simplest solution is to just not use threading.

What you are trying to do is wait a duration and then run a coroutine. This can be done with a background task (example)

async def status_task():
    while True:
        await test_bot.change_presence(...)
        await asyncio.sleep(10)
        await test_bot.change_presence(...)
        await asyncio.sleep(10)

@test_bot.event
async def on_ready():
    ...
    bot.loop.create_task(status_task())

You cannot use time.sleep() as this will block the execution of the bot. asyncio.sleep() though is a coroutine like everything else and as such is non-blocking.

Lastly, the @client.event decorator should only be used on functions the bot recognises as events. Such as on_ready and on_message.