Как остановить бесконечный цикл командой стоп, которую пишет пользователь в чате телеграм бота? Python

Есть многопользовательский телеграм бот, который по команде запускает парсинг объявлений с сайта. Вызывается функция start_parsing, запускается цикл While True. При получении в чате команды стоп, хендлер ловит команду и вызывается функция stop_parsing, которая должна остановить работу бесконечного цикла

@dp.message_handler(Text(equals="start"))
async def start_parsing(message: types.Message):
    await bot.send_message(chat_id=message.from_user.id, text="парсинг запущен")
    while True:
        #тут код с парсингом


@dp.message_handler(Text(equals="stop"))
async def stop_parsing(message: types.Message):
    #тут код, который останавливает цикл While True из функции "start_parsing"
    await bot.send_message(chat_id=message.from_user.id, text="парсинг остановлен")

Частично проблема решилась созданием глобальной переменной parsing_continue. Цикл While при каждой итерации проверяет, что она равна True. А по команде стоп в функции stop_parsing эта переменная становится False. Но это работает только для 1 пользователя. Когда их несколько, команда стоп тормозит парсер всех других пользователей, т.к. переменная глобальная

global parsing_continue


@dp.message_handler(Text(equals="start"))
async def start_parsing(message: types.Message):
    await bot.send_message(chat_id=message.from_user.id, text="парсинг запущен")
    global parsing_continue
    parsing_continue = True
    while parsing_continue:
        #тут код с парсингом


@dp.message_handler(Text(equals="stop"))
async def stop_parsing(message: types.Message):
    global parsing_continue
    parsing_continue = False
    await bot.send_message(chat_id=message.from_user.id, text="парсинг остановлен")

Возможно, в варианте с глобальной переменной поможет словарь, в котором ключом будут динамически создаваемые переменные parsing_continue, привязанные к id пользователя. Или существует более подходящая конструкция, чем блокирующий цикл While True. Может можно как-то создать задачу, которая будет активироваться при старте, и сниматься при стопе.

Сам в питоне новичок, с языком знаком по библиотеке aiogram для ботов. Нагуглил варианты с событийными циклами, creating task, event-loop и тд... Пока не разобрался, это то что нужно, или нет. Подозреваю, что это целая тема для изучения. Буду благодарен если подскажите куда вообще копать


Ответы (1 шт):

Автор решения: oleksandrigo

Записывайте parsing_continue в хранилище стейта.

from aiogram.dispatcher import FSMContext
from aiogram.contrib.fsm_storage.memory import MemoryStorage

dp = Dispatcher(bot, storage=MemoryStorage())

@dp.message_handler(Text(equals="start"))
async def start_parsing(message: types.Message, state: FSMContext):
    await bot.send_message(chat_id=message.from_user.id, text="парсинг запущен")
    # записываете в хранилище
    await state.update_data({"parsing_continue": True})
    # обязательно чтобы делалось именно так, не нужно это в переменную записывать
    while (await state.get_data()).get("parsing_continue"):
        print(1)
        await asyncio.sleep(5)


@dp.message_handler(Text(equals="stop"))
async def stop_parsing(message: types.Message, state: FSMContext):
    # просто обновляем данные
    await state.update_data({"parsing_continue": False})
    await bot.send_message(chat_id=message.from_user.id, text="парсинг остановлен")
→ Ссылка