Параллельная обработка сообщений от пользователей в Telegram
Сделал хорошенького бота в телеграме, но вот незадача, он синхронный. Если им будут пользоваться несколько пользователей одновременно, то он сначала выполнит команду одного, потом другого и т.д...
У меня есть хендлер команды start - ничего сложного, просто вывод сообщения. Есть хендлер на сообщение. Я отправляю в бот сообщение, он его валидирует и запускает определенную функцию. На время работы функции ввод в бота блокируется. Если попытаться ввести новое сообщение, бот просто будет присылать сообщение типа "делаю задачу, как выполню, так пишите". После выполнения функции, можно спокойно отправлять новое сообщение боту. В случае синхронного бота на Telebot`е, если пользователь 1 отправит сообщение, он запустит выполнение функции, а значит, пользователь 2, при отправке сообщения, получит блокировку в боте - "делаю задачу, как выполню, так пишите". Но сообщение п-ля 2 не встанет в очередь, ему нужно заново писать его.
Я недавно узнал, что Telebot стал поддерживать асинхронность. Я попытался проверить. В таком случае, выполнение функции встало в очередь. Неважно кто писал в бота - несколько сообщений от п-ля 1 или поочередные от п-ля 1 и п-ля 2. Перестала работать блокировка. А это вообще не то, что мне нужно.
Успешных кейсов море, но я не нашел ни одной подходящей реализации для того, чтобы применить на своем проекте.
А нужно:
- П-ль 1 и п-ль 2 отправят сообщение в бота, и для каждого из них будет выполняться свой экземпляр функции, то есть параллельно, получая и обрабатывая индивидуальные данные.
- Блокировка ввода для каждого пользователя должна работать, как в случае синхронности (нельзя отправить сообщение, пока обрабатывается предыдущее).
Код синхронного бота (асинх не сохранял после тестов):
# import`ы
bot = telebot.TeleBot('токен')
search_in_progress = False
def generate_and_check(code):
global search_in_progress
# Блокировка функции на время выполнения
search_in_progress = True
path_1 = f"path 1 {code}"
path_2 = f"path 2 {code}"
text = f"text + {path_2})"
# Что-то происходит несущественное...
try:
# Работа с path_1 - получаем data_1 и возвращаем вместе с path_1, text:
return path_1, data_1, text
except Exception as e:
print(e)
# Если в работе с путями возникли проблемы:
return path_1, None, text
finally:
# Завершаемся и отбой блокировки
search_in_progress = False
@bot.message_handler(commands=['start'])
def handle_start(message):
bot.send_message(message.chat.id, "Привет!")
# Обработчик сообщения
@bot.message_handler(func=lambda message: True)
def handle_input(message):
global search_in_progress
# Проверка на блокировку и валидация сообщения
if not search_in_progress and re.match(r'123', message.text):
# Получаем код из сообщения
message_code = message.text
bot.send_message(message.chat.id, f"Ваш код {message_code}")
# Происходит некоторая проверка...
# Вызываем generate_and_check, передаем в него message_code и получаем return`ы
path_1, data_1, text = generate_and_check(message_code)
# Если с путями все ОК
if path_1 and data_1 is not None:
result_message = f"ОК - {message_code}\n{data_1} {path_1} {text}"
bot.send_message(message.chat.id, result_message)
# Если с путями все НЕ ОК
else:
data_1 = "ВАЩЕ НЕ ОК"
result_message = f"НЕ ОК - {message_code}\n{data_1} {path_1} {text}"
bot.send_message(message.chat.id, result_message)
# Работа блокировки
elif search_in_progress:
bot.send_message(message.chat.id, "Занято н....й!")
# Работа валидации
else:
bot.send_message(message.chat.id, "Сообщение невалидно")
if __name__ == "__main__":
bot.polling(none_stop=True)
Код я обезличил, оставил то, с чем можно поработать, остальное к делу не относится.
Вопрос(ы):
- Можно ли это адекватно поставить на асинхронного Telebot`a, в соответствии с пожеланиями выше? Как?
- Рассмотрю aoigram3. У меня недостаток опыта работы с асинхронностью, поэтому обрубил синхронным ботом руки себе заранее. Как на нем можно это реализовать?
- Костыли? На худой конец сойдет...