FSM Aiogram таймер сброса состояний
Мой вопрос частично перекликается с этим: Auto Stop FSM mashine. Python Aiogram
Есть цепочка состояний FSM и есть кнопка отмены. Но допустим, пользователь на вводе возраста или пола решил что ему это больше не интересно, он не нажал кнопку отмены и вышел из бота. Если таких будет не 1 а 100 наверно лучше как-нибудь автоматом сбрасывать такие состояния? По времени не активности, например (если пользователь надолго задерживается в одном из состояний)? Я пробовал разные комбинации в хендлере, используя asyncio.sleep() и они все работали, пока бот запускался в режиме polling. Но на webhooks он начинает подвисать попадая в хендлер с asyncio.sleep() и вызывает срабатывание сброса почти сразу (время указанное в скобках не проходит и никаких ошибок не выдает). Использовать sleep в асинхронном боте мне кажется плохим решением, но ничего больше не могу придумать. Я только начинаю разбираться с Aiogram, прошу прощения за путанное описание.
Ответы (1 шт):
Эта функция принимает три аргумента: user_id, state, timeout=300.timeout — это количество секунд, по истечении которых состояние будет сброшено, если пользователь не написал новое сообщение. В этом случае тайм-аут устанавливается на 5 минут.
Сначала функция извлекает время последнего сообщения пользователя из last_message_time в словаре состояний. Если значение равно None, это означает, что это первое сообщение пользователя, поэтому текущее время сохраняется в ключе last_message_time.
В противном случае функция вычисляет время с момента последнего сообщения, вычитая last_message_time из текущего времени. Если это время больше тайм-аута, функция сбрасывает состояние с помощью state.reset_state() и обновляет last_message_time текущим временем.
import asyncio
async def reset_fsm_state(user_id, state, timeout=300):
last_message_time = state.get('last_message_time')
if last_message_time is None:
# First message, save the time
state['last_message_time'] = asyncio.get_running_loop().time()
return
current_time = asyncio.get_running_loop().time()
time_since_last_message = current_time - last_message_time
if time_since_last_message > timeout:
# User has not written a new message within 5 minutes, reset the state
state.reset_state()
state['last_message_time'] = current_time