Отмена таймера из другой функции другого модуля (aiogram)
Всем доброго времени суток! Пишу бота для телеги с помощью библиотеки aiogram, и возникла небольшая проблема.
Суть: в модуле payments.py есть хэндлер, при срабатывании которого инициализируется таймер из модуля timer.py. Нужно, чтобы при срабатывании другого хэндлера (уже из другого модуля confirm.py) созданный в payments.py таймер отменялся. Код:
# Модуль timer.py
import asyncio
class Timer:
def __init__(self, time, query, state, callback):
self._timeout = time
self._query = query
self._state = state
self._callback = callback
self._task = asyncio.ensure_future(self._job())
async def _job(self):
await asyncio.sleep(self._timeout)
await self._callback(self._query, self._state)
def cancel(self):
self._task.cancel()
Модуль payments.py
@dp.callback_query_handler(state=MakeTask.chooseTime)
async def choosePayment_cb(query: CallbackQuery, callback_data: dict, state: FSMContext):
timer = Timer(60, query, state, timeout)
async def timeout(query, state):
await bot.edit_message_text(chat_id=query.message.chat.id, message_id=query.message.message_id,
text=f'Время истекло')
Модуль confirm.py
@dp.callback_query_handler(state=MakeTask.confirm)
async def confirm_cb(query: CallbackQuery, callback_data: dict, state: FSMContext):
# Тут нужно отменить таймер командой timer.cancel(), но как передать экземпляр timer в текущий хэндлер?
Пересмотрел очень много материала на разных сайтах и нигде не смог найти подходящее решение. Вообще нет идей ввиду недостатка опыта. Подскажите, пожалуйста, как это реализовать? Спасибо!
UPD1: Мне понравилось предложение @eri, почитал информацию, небольшое продвижение есть. Но опять застрял :С Как мне добавить проверку на этот эвент? Попробовал такой вариант, но он мне не подходит, нужно, чтобы как только эвент происходил, так сразу же отменялся таймер. Код:
async def _run_timer(self, time, cancel_event):
print("Таймер запущен!")
seconds = 0
while seconds < time:
if not cancel_event.is_set():
await asyncio.sleep(1)
seconds += 1
else:
self.cancel(cancel_event)
print('Таймер успешно завершён!')
await self._callback()
def cancel(self, cancel_event):
cancel_event.clear()
print('Отмена таймера!')
self._task.cancel()
Ответы (1 шт):
Выражаю огромную благодарность @eri за предложенную идею. В течение нескольких дней пытался реализовать "идеальный" для себя таймер, который как только получает event, так сразу отменяет таймер и сразу же выполняет callback, предназначенный для отмены. Но, увы и ах, не вышло. Пришлось немного покостылить. Надеюсь, кому-нибудь поможет даже такой экзотичный способ отмены таймера.
Модуль timer.py:
import asyncio
cancel_event = asyncio.Event()
class Timer:
def __init__(self, time, query, state, event, callback):
self._timeout = time
self._query = query
self._state = state
self._cancel_event = event
self._callback = callback
self._task = asyncio.ensure_future(self._job())
async def _job(self):
seconds = 0
while seconds <= self._timeout:
if not self._cancel_event.is_set():
await asyncio.sleep(0.1)
seconds += 0.1
else:
await self.cancel()
await self._callback(self._query, self._state)
async def cancel(self):
self._task.cancel()
# Тут код, который должен выполняться при отмене таймера
self._cancel_event.clear()
Модуль confirm.py:
from timer import cancel_event
@dp.callback_query_handler(state=MakeTask.confirm)
async def confirm_cb(query: CallbackQuery, callback_data: dict, state: FSMContext):
cancel_event.set()
while cancel_event.is_set():
await asyncio.sleep(0.1) # Ожидание, пока эвент отмены полностью не завершится
# Дальнейший код, который не должен выполняться, пока полностью не завершится функция в колбэке отмены
Всем спасибо!