If I use a helping function for a discord.py command, should I use await to call my helping function or just transfer control to my async helper

Question:

I have a command that works to send multiple type of messages that follow the same structure but I am using a helping function to send the message. For simplicity, my code looks similar to this:

Option 1:

async def helper(context: Context, msg_type: str, param1, param2, ...):
    # Some code to create the message to be sent ...
    embed = discord.Embed(description=message)
    await context.send(embed=embed)

@commands.hybrid_command(
   name="run",
   description="Sends a reminder to run."
)
def run(context: Context, param1, param2, ...):
    # Some input validation for run command ...
    helper(context, 'run', param1, param2, ...)

@commands.hybrid_command(
   name="walk",
   description="Sends a reminder to walk."
)
def walk(context: Context, param1, param2, ...):
    # Some input validation for walk command ...
    helper(context, 'walk', param1, param2, ...)

Option 2 is making every function async and calling helper with await.

It is my first time creating a discord bot and working with async/await. I have read that the rule of thumb for async/await is using async where you need to await for some computing, specially if it’s external to your code like an API.

  1. I would appreciate some guidance to understand where I should or not use async/await in my discord bot or in general. For the sake of efficiency, suppose that this bot is going be executed by 100k+ users (if this needs to be considered) and that the helper function also involves calling an API other than discord.
  2. I only find approaches to bot commands where 1 command = 1 action, are there recommendations to implement composed commands? Maybe my command should instead be to call my helper function (say /send run or /send walk) with the message type as the first command?
Asked By: Luis Quiñones

||

Answers:

Option 1 is a bad idea. You should always await asynchronous functions (unless in your main where you don’t have a choice but to use something like the asyncio library to get it started, but that doesn’t apply here).

In other words, Option 2 is the way to go. The only thing you have to change is add an extra word in front of your command callback, so it really doesn’t make any difference to you as a developer. Furthermore, this will allow you to call other async functions which will be of great use. There’s no reason at all not to go for Option 2.

I would appreciate some guidance to understand where I should or not use async/await in my discord bot or in general.

You should use it wherever you can, but mainly for slow parts that can take a few seconds (if not more). If everything in your bot is synchronous, your entire bot will freeze until the command is finished. If it is going to be executed by "100k + users", imagine 100k+ commands sitting in a queue because each of them has to get executed one by one. Your bot would literally freeze for minutes on end.

For more information regarding "blocking", read the Discord.py docs: https://discordpy.readthedocs.io/en/stable/faq.html#what-does-blocking-mean

Basically: if you can make it async, you have no reason not to make it async. You shouldn’t ever have to think "Should I make this part async?" The answer will practically always be "yes".

and that the helper function also involves calling an API other than discord.

API calls should always be asynchronous. A request can take up to multiple seconds. If your bot has 100k+ users, and only 100 of them (0.1%) run that command at the same time, that’s hundreds of seconds where your bot won’t be responding at all. The docs page about blocking already explains how to make asynchronous API calls.

Imagine if I use a command that makes an API request to a very slow server. Do you think your 100.000+ users will be okay with your whole bot becoming unresponsive for 30 seconds because one single person called one single command that happened to make a single slow request?

The same concept applies to database interaction. With hundreds of thousands of users, queries will inevitably start to slow down a bit. You wouldn’t want your bot to also become unbearably slow because it spends 95% of its time waiting for database queries to complete, would you?

I only find approaches to bot commands where 1 command = 1 action, are there recommendations to implement composed commands?

Not entirely sure what you mean with this – would you care to explain it in a bit more detail?

Answered By: stijndcl