Telegraf handles all requests sequentially, one after another. I won't get into details about why it might be done like that by default, but sometimes it's not really what you want.
So I had this problem too. While the bot was handling one heavy command, it could not handle other commands at the same time. Even if they were in different chats. That was quite a problem for me.
I didn't dive inside Telegraf, instead I just came up with a guess and it worked. I'm just sharing my experience, you might need to tweak the code for yourself a little.
bot.use((ctx, next) => void next())
Why? I thought, if Telegraf awaits promises returned from handler functions for some reason, then I can just replace them with undefined
(using middleware), so there will be nothing to await.
I think this is a pretty bad solution, why - read below.
I believe this is a better option. In the very bottom of the note I'll explain why.
const stacks = new Map()
export function makeParallel() {
return (ctx, next) => {
const key = `${ctx.from?.id ?? 0}-${ctx.chat?.id ?? 0}`
if (!stacks.has(key)) stacks.set(key, Promise.resolve())
const stack = stacks.get(key)!
stacks.set(
key,
stack.finally(() => next())
)
}
}
bot.use(makeParallel())
The same idea is behind this code, but it also avoids the issue, which I'll explain right below.
Let's say you have a shop bot. The user has balance of 101, and the service costs 100. The user of course should not be able to buy something if he doesn't have enough money.
And when you enter the /buy
command let's say, the bot has to process some information for 10 seconds before returning some answer to the customer.
The customer sends /buy
and right after that does it (/buy
) one more time.
Let's see how it will work in two cases:
- The bot checks the balance: 101 > 100. Pass.
- The bot does its work for 10s.
- The bot removes 100 from user's balance: 101 -> 1.
- The bot returns the result to the customer.
- The bot checks the balance. 1 < 100. Fail.
- The bot checks the balance: 101 > 100. Pass.
- The bot checks the balance: 101 > 100. Pass.
- The bot does its work for 10s.
- The bot does its work for 10s.
- The bot returns the result to the customer.
- The bot returns the result to the customer.
- The bot removes 100 from user's balance: 101 -> 1.
- The bot removes 100 from user's balance: 1 -> -99.
So as you can see, the bot did the work twice, even though the user didn't have enough money. He had even gone overdraft.
If you know hot to make this article better (better code, examples, explainations etc.), write me in Telegram: @social_pressure