Reputation: 51
This question is outdated now as after python-telegram-bot
v20.0 it was rewritten in an asyncio
manner. Now, all callbacks should be asynchronous functions.
I have a question that has been bothering me for a long time. I would greatly appreciate your help!
Let's imagine a situation like this:
You entered a function by a command. In this particular function, there is a loop that takes a long time to finish, or worse, it is actually an infinite loop. The question is, how can you abort this loop or function so that the bot can handle other requests?
An example would be like this:
def function(update, context):
counter = 0
message = update.message.reply_text(str(counter))
while True:
counter += 1
message = message.edit_text(text = str(counter))
time.sleep(1)
dispatcher.add_handler(CommandHandler("main", function))
After user enters this function by "/main", he or she gets a message that includes a number, which the number increases every second and this will take forever to finish.
Something that I have tried:
Design another MessageHandler
, if user sends some keywords like "stop", it changes the value of a global variable. In the loop, it checks if this variable is True
every time before it adds the number, if it was False
, it breaks.
However, the MessageHandler won't detect this message before the loop has actually ended, so this is meaningless.
Include a InlineKeyboard
in the message, with a button called "Stop". Design another CallbackQueryHandler
to handle this button.
Similarly, CallbackQueryHandler will only receive the callback after the loop was finished. This can be verified if I set a manual break
when the counter hits a number like 5 or something.
I was thinking if I could design some kind of abort function that runs asynchronously, but I am personally not very familiar with async in Python. After some trials like setting async def
or CallbackQueryHandler(query_handle, run_async = True)
, I still failed to produce this effect.
I noticed there is a decorator called from telegram.ext.dispatcher import run_async
, does that help? Or, is there any other way to realize this result?
Thanks!
Upvotes: 5
Views: 9343
Reputation: 1136
Examples how to configure handlers to be run in anync mode for python-telegram-bot==13.13
(run_async=True
is passed to handlers):
dispatcher.add_handler(CommandHandler(["zip_and_send_all_logs", "zsal"],
zip_and_send_all_logs_cmd, run_async=True))
dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command,
run_sh_cmd_for_text_msg, run_async=True))
Also there is @run_async
decorator function in
from telegram.ext.dispatcher import run_async
which can be used to mark handler to be run in async mode. But this decorator was deprecated. Recommended way is to pass run_async
parameter to handlers. Its default value is False
.
Related question: Is python-telegram-bot suitable for async job? #877
Upvotes: 2
Reputation: 7050
By default Dispatcher
handles the incoming updates one by one. That's why your first two approaches can't work. What you can do is run the loops in a standalone thread. This is in fact, what the run_async
parameter is there for - it has nothing to do with asyncio
programming. See this wiki page for detailed information about run_async
. Also note that the next major version of PTB will introduce asyncio
to PTB - see this announcement.
I'd like to point out that a while
loop + time.sleep()
might not be the best idea anyway, especially if the sleep-time is significant. An alternative would be to schedule a repeating job. PTB has the built-in JobQueue
for that.
Disclaimer: I'm currently the maintainer of python-telegram-bot
.
Upvotes: 7