Используя библиотеку PyTelegramBotAPI я столкнулась с тем, что написанный мною бот работает мягко говоря не очень - когда ботом одновременно пользовалось несколько человек сообщения пересекались, записывались левые данные, да и вообще творилась какая-то вакханалия.

Хочу отметить, что я только начинаю свой путь и в данной статье по случайности могла написать какой-то бред, пожалуйста, не судите строго, если что - поправляйте)

Итак, предлагаю рассмотреть пример кода:

import telebot

bot = telebot.TeleBot('токен')
 возможные состояния пользователя
@bot.message_handler(commands=['start'])
def hello_message(message):
    id1 = message.from_user.id
    bot.send_message(message.chat.id, f'Ваш id {id1}')

Здесь мы можем видеть небольшой кусок кода. Человек пишет команду /start и мы выдаем ему его id.

Вообще, этот кусок скорее всего будет работать без проблем, но если это всего лишь часть проекта, где нам нужно запомнить id и передавать его далее в другие функции, мы увидим проблемы.

Какие?

Представим ситуацию: два пользователя плюс минус в одно время нажали /start. Сначала код выполняется у первого и записывается его id, аналогично происходит и со вторым. В переменную id1 последним записался id второго пользователя, и да, самое главное - он будет доступен и будет пересекаться с другими пользователями! Функции доступны для взаимодействия для всех пользователей одинаково, и если один пользователь с нашей первой функции, рассмотренной в примере, переходит уже на следующую, куда будет передан его id, а потом второй пользователь перейдет в эту функцию, в конечном итоге запишется id второго пользователя! Это ужасно...)

Как же исправить этот недуг?

Я пять часов пыталась понять как исправить это, и знаете, все оказалось довольно таки просто. Вот новый, обновленный код:

import telebot
import random
bot = telebot.TeleBot('')
states = {}  # словарь для хранения состояний пользователей

START = range(1)  # возможные состояния пользователя
@bot.message_handler(commands=['start'])
def hello_message(message):
    secret = 0
    states[secret] = START
    secret = random.randint(1,49494985894939494944)
    states[secret] = START
    id1 = message.from_user.id
    bot.send_message(message.chat.id, f'Ваш id {id}')

Что же мы здесь видим?

Я добавила в этот код так скажем строки состояний. START = range(1) - это все возможные состояния пользователей - их может быть сколько угодно, в зависимости от функционала вашего бота и располагать их надо в каждой функции. Изначально был создан словарь states, он создавался вне всех функций. В первой функции, в самом ее начале, нам необходимо создать любую переменную (в нашем случае secret), и в эту переменную нужно записывать рандомное значение, которое не должно будет повторяться, затем передавать эту переменную далее в другие функции и аналогично писать в начале каждой функции states[secret] = (тут состояние пользователя). Я использую модуль random для генерации рандомного значения. Теперь при входе в функцию у каждого пользователя будет генерироваться свой, скажем, ключ идентификации, и другой пользователь не сможет получить доступ к этой функции.

Да, secret = 0
states[secret] = START
secret = random.randint(1,49494985894939494944)
states[secret] = START

выглядит странно, наверное, можно обойтись и без первых двух строчек, но я зачем-то, видимо на всякий случай, сделала так

Вообщем теперь ничего пересекаться не будет, после входа в каждую функцию у каждого пользователя будет генерироваться свой ключ, который далее будет передаваться в другие функции методом register_next_step_handler(), таким образом, наш бот получил режим многопользовательности:)

Спасибо за внимание) Надеюсь, кому-нибудь это поможет)

Комментарии (6)


  1. bagman2020
    17.08.2024 11:38
    +1

    А рассматривали ли вы возможность использования более надежного способа хранения состояний пользователей, например, базы данных или системы кэширования, такой как Redis, вместо простого словаря? Я думаю это могло бы обеспечить большую масштабируемость и надежность, особенно если ваш бот должен обслуживать большое количество пользователей.


  1. wesp1nz
    17.08.2024 11:38
    +1

    Не проще aiogram юзать? Ну а если код синхронный, то отдельный поток создавать)


  1. d-sh
    17.08.2024 11:38
    +1

    В первом примере кода никаких проблем не будет. Там локальная переменная id1 и она ни с кем пересекаться не будет. Она там вообще не нужна и по сути ничего не делает.

    Во втором примере кода тоже самое + еще какие то ничего не делающие манипуляции.


  1. zoto_ff
    17.08.2024 11:38

    тот самый момент, когда вместо использования нормальных фреймворков в ход идут лютейшие "хаки" и горы костылей


    1. d-sh
      17.08.2024 11:38

      Не, это другой случай. Это нормальная библиотека.


  1. kiff2007200
    17.08.2024 11:38

    Так а у вас же уже есть уникальный id - message.from_user.id . Вы можете использовать его, а не генерировать новый с риском, что сгенерируется повторный. Также можно создать структуру, в которой хранятс id и другие данные пользователя, например состояния, и передавать эту структуру в следующие функции.