Как сделать асинхронный счетчик/триггер на время?
Пишу телеграм бота на aiogram. Ботом будет пользоваться большое кол-во людей и в боте есть модуль заказа.
Задача этого модуля - создание заказов, которые должны закрываться в какие-то указанные сроки.
Допустим бот запрашивает дату и время закрытия заказа, пользователь вводит дату: 2022-08-17 и время: 19:00. И наш заказ должен будет закрыться 2022-08-17 числа в 19:00.
Опять же, нужно не забывать, что таких заказов будет много и мне нужен какой-то оптимизированный и асинхронный вариант для этой задачи, спасибо
Ответы (1 шт):
Как костыльный вариант предлагаю это.
Его проблема в том что если бот перезапустится все отсчеты исчезнут.
По красивому, стоит сделать отдельную таску которая каждую минуту или час проверяет из бд все заказы, которые у вас в data['datetime'](и которые нужно туда занести).
import asyncio
from aiogram import Bot, Dispatcher, executor, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import StatesGroup, State
from datetime import datetime, timedelta
import config
bot = Bot(token=config.BOT_TOKEN)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)
class InputDateTime(StatesGroup):
input_date = State()
input_time = State()
@dp.message_handler(commands=['start'])
async def start(message: types.Message):
await message.answer("Введите дату в формате 'ДД-ММ-ГГГГ'")
await InputDateTime.input_date.set()
@dp.message_handler(state=InputDateTime.input_date)
async def input_date(message: types.Message, state: FSMContext):
res = message.text.split("-")
if len(res) == 3 and all(map(lambda date: date.isdigit(), res)):
async with state.proxy() as data:
if len(res[2]) == 4:
data['date'] = res
await message.answer("Введите время в формате 'ЧЧ-ММ'")
await InputDateTime.next()
return
await message.answer("Неверный формат даты")
@dp.message_handler(state=InputDateTime.input_time)
async def input_time(message: types.Message, state: FSMContext):
res = message.text.split("-")
if len(res) == 2 and all(map(lambda date: date.isdigit(), res)):
hour, minute = res
async with state.proxy() as data:
day, month, year = data['date']
day, month, hour, minute = map(lambda number: f"{int(number):02}", (day, month, hour, minute))
del data['date']
data['datetime'] = datetime.strptime(f"{day}/{month}/{year} {hour}:{minute}", "%d/%m/%Y %H:%M")
if data['datetime'] > datetime.now():
print("заказ принят")
await asyncio.sleep(timedelta.total_seconds(data['datetime'] - datetime.now()))
await message.answer("Время пришло")
else:
await message.answer("Неверный формат даты")
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)