@Dbtzhv

Как отложить выполнение функции в aiogram?

Проект джанго+aiogram бот. У бота есть рассылка постов/опросов. Вот как она работает:
Manager/admin создаёт экземпляр модели Post/Poll в админ-панели джанго -> Админ подтверждает/нет рассылку, отправлению ему в лс телеграма, которая была ему отправлена после создания-> если подтверждает ("post" callback data) -> do_mailing функция в хэндлере "post" сразу же отрабатывает

Но я добавил "scheduled_time = models.DateTimeField" поле в мои Post/Poll модели и хочу чтобы do_mailing в хэндлере отрабатывала один раз в указанную в поле scheduled_time дату.

модель Поста:
class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='Менеджер')
    text = models.TextField(verbose_name='Текст')
    scheduled_time = models.DateTimeField(blank=True, null=True, verbose_name="Дата и время рассылки")
    approved = models.BooleanField(default=False, verbose_name='Подтверждён')
    total_media_count = models.PositiveIntegerField(default=0, verbose_name='Сколько фотографий загрузите?')
    group = models.ForeignKey('bot_users.BotUserGroup', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='Группа пользователей бота')
    created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name='Создано')


Хэндлер для "post" callback data, которая отправляется после подтверждения админа
@dp.callback_query_handler(lambda query: query.data == 'post', state="*")
async def post_handler(callback_query: CallbackQuery, state: FSMContext):
    admin = callback_query.message['chat']['id']
    message = callback_query.message.text.split('\n')
    await change_post_status(message[0].split(': ')[1])
    await do_mailing(message)
    logging.info(f"Пост {message[0].split(': ')[1]} был одобрен на рассылку админом")
    await bot.send_message(chat_id=admin, text=f"Рассылка поста {message[0].split(': ')[1]} одобрена!")
    await bot.send_message(chat_id=message[-1].split(': ')[1].split(' ')[0], text=f"Рассылка поста {message[0].split(': ')[1]} одобрена!")


Т.е. do_mailing - это функция, которую я хочу отсрочить. Я смогу получить "scheduled_time"-поле из переменной message, поэтому просто представим, что в хэндлере будет значение scheduled_time нужного экземпляра.

А вот как именно отложить do_mailing в хэндлере, имея нужную дату рассылки, я и спрашиваю.
  • Вопрос задан
  • 314 просмотров
Пригласить эксперта
Ответы на вопрос 2
Vindicar
@Vindicar
RTFM!
Создай через create_task() долго работающую задачу, которая будет периодически опрашивать запланированные расссылки, искать те, которые "уже пора" и запускать их на выполнение. А потом спать некоторое время до очередной проверки. Эта задача должна стартовать параллельно с ботом.
Такой способ может вносить погрешность в точное время рассылки (условно, проверяешь раз в час - время можно задать только с точностью до часа). Но зато он гораздо менее рискован. Упрощённо, если ты сделал await asyncio.sleep(сколько_нужно), а за это время бот упал и был перезапущен, бот просто не "вспомнит" о ранее запланированных, но не выполненных рассылках.
Ответ написан
Комментировать
@SerdarAD
Можно ждать через asyncio.sleep()
А функцию запускать через asyncio.create_task(do_malling(message))
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы