Использование обработчиков бота, по умолчанию, асинхронно (run_async=True)
В библиотеке python-telegram-bot обработка запросов, по умолчанию, выполняется последовательно.
Для параллельной работы использовался декоратор @run_async, который во все функции-обработчики нужно было добавлять, пример:
import threading
from telegram import Update
from telegram.ext import Updater, MessageHandler, Filters, CallbackContext
from telegram.ext.dispatcher import run_async
@run_async
def on_request(update: Update, context: CallbackContext):
message = update.effective_message
message.reply_text(f'Thread: {threading.current_thread()}')
if __name__ == '__main__':
updater = Updater(TOKEN)
dp = updater.dispatcher
dp.add_handler(MessageHandler(Filters.text, on_request))
updater.start_polling()
updater.idle()
Но с версии 13, декоратор устарел и вместо него библиотека предлагает использовать одноименный параметр в обработчиках Handler или запускать функции через метод Dispatcher.run_async (что немного не то):
TelegramDeprecationWarning: The @run_async decorator is deprecated. Use the `run_async` parameter of your Handler or `Dispatcher.run_async` instead.
return self.callback(update, context)
Использование параметра run_async=True работает:
import threading
from telegram import Update
from telegram.ext import Updater, MessageHandler, Filters, CallbackContext
def on_request(update: Update, context: CallbackContext):
message = update.effective_message
message.reply_text(f'Thread: {threading.current_thread()}')
if __name__ == '__main__':
updater = Updater(TOKEN)
dp = updater.dispatcher
dp.add_handler(MessageHandler(Filters.text, on_request, run_async=True))
updater.start_polling()
updater.idle()
Но возникла проблема перехода на параметр run_async=True вместо декоратора @run_async
Ведь нужно сделать следующие вещи во всех поддерживаемых ботах:
- Убрать импорт декоратора
from telegram.ext.dispatcher import run_async - Убрать декоратор
@run_asyncво всех функциях-обработчиках - Всем обработчикам указать параметр
run_async=True- Кстати, это касается и метода добавления обработчика ошибок Dispatcher.add_error_handler
Есть боты, у которых обработчиков может быть ~50. Труднозатратно каждому обработчику указывать тот параметр. Конечно, можно оставить старую версию, но если хочется обновить версию, то что можно тут сделать?
Как менее болезненно перейти на асинхронный режим работы бота?
PS.
Понять работает функция-обработчик в отдельном потоке можно по названию потока, что вернется от бота при f'Thread: {threading.current_thread()}'.
Вот это без потоков:
Thread: <Thread(Bot:{id бота}:dispatcher, started 772)>
А этот в потоке:
Thread: <Thread(Bot:{id бота}:worker:a36abf98-33a8-4c73-8c02-51a3e5241b5e_0, started 26488)>
Ответы (1 шт):
Первое, что пришло в голову это пройтись по всем обработчикам и принудительно указать им run_async = True:
...
for commands in dp.handlers.values():
for command in commands:
command.run_async = True
updater.start_polling()
updater.idle()
Это работает
Но такое решение костыльное, есть способ лучше
В библиотеке есть класс Defaults (по-моему, он появился как раз с 13 версии), у этого класса есть поле run_async и объект класса можно передавать в настройки бота.
Помимо того, что использование Defaults является официальным API, это еще влияет на значения по-умолчанию, например, если в каких-то случаях не нужно обработки асинхронно, то можно указать это в обработчике и это не поменяется при установке Defaults(run_async=True), в отличии от способа выше:
MessageHandler(Filters.text, on_request, run_async=False),
import threading
from telegram import Update
from telegram.ext import Updater, MessageHandler, Filters, CallbackContext
from telegram.ext.defaults import Defaults
def on_request(update: Update, context: CallbackContext):
message = update.effective_message
message.reply_text(f'Thread: {threading.current_thread()}')
if __name__ == '__main__':
updater = Updater(
TOKEN,
defaults=Defaults(run_async=True),
)
dp = updater.dispatcher
dp.add_handler(MessageHandler(Filters.text, on_request))
updater.start_polling()
updater.idle()