0

I noticed that the on_message event handler can only handle 1 message at a time.

So when we need to process some time_consuming tasks inside it, it will actually block the bot from handling messages come in later.

In the example below, if the user sends two or more messages in a row quickly, the bot will pick up the first message and start processing it, but it won't process the second message until it finishes the first one and sends the result back, in this case, say it will take minutes to execute that get_result_from_time_consuming_task function. It will actually block all incoming messages while doing it.

I was trying to implement multi-thread to process the time consuming task, but after playing around, I couldn't get the message sending to work with it.

@client.event
async def on_message(message):
   result = get_result_from_time_consuming_task()
   sent_message = await message.channel.send(result)
Jerry
  • 81
  • 8
  • 3
    With proper asynchronous code, `on_message` will be able to handle multiple messages at the same time. Most likely `get_result_from_time_consuming_task()` is blocking and you will to rewrite it to be asynchronous. If you can't rewrite it to be asynchronous, then you can put it in a thread. See example [here](https://stackoverflow.com/questions/53587063/using-subprocess-to-avoid-long-running-task-from-disconnecting-discord-py-bot/53597795#53597795). – Benjin Nov 29 '21 at 07:18

2 Answers2

0

I end up doing this to avoid blocking from async and await code

async def on_message(message):
   thread = threading.Thread(target=perform_time_consuming_task, args=(message,))
   thread.start()

def perform_time_consuming_task(message):
   # slow code here
   client.loop.create_task(message.channel.send("your result"))
Jerry
  • 81
  • 8
-1

You can make use of asyncio.create_task(a_coroutine(message.channel)), this line of code will be non-blocking, so the function will be ready to be called again on the next message

And your coroutine will be something like

async def a_coroutine(channel):
    result = get_result_from_time_consuming_task()
    sent_message = await channel.send(result)

If this doesn't work, maybe you should start looking into Cogs https://discordpy.readthedocs.io/en/latest/ext/commands/cogs.html#ext-commands-cogs

I also have a discord bot with a pretty complicated on_message behaviour, but when two messages are sent as fast as humanely possible, the behaviour of the on_message is still triggered for the two message (it adds 2 reaction to each message, and it does first reaction first message, first reaction second, second reaction first and second reaction second) so I think it might be due to a different implementation of the @client.event compared to @commands.Cog.listener()

Nathan Marotte
  • 771
  • 1
  • 5
  • 15
  • I tried your solution, but the coroutine function is still blocking the incoming messages from being processed. – Jerry Nov 30 '21 at 05:02