diff --git a/bot.py b/bot.py index c591740..4dbfb64 100644 --- a/bot.py +++ b/bot.py @@ -1956,8 +1956,40 @@ class VKBotApplication: time.sleep(0.4) # троттлинг против лимитов VK self.send_message(admin_id, f"✅ Рассылка завершена. Доставлено получателям: {sent} из {len(recipients)}.") + def _check_due_reminders(self): + """Проверяет и рассылает напоминания, чьё время наступило. + Вызывается фоновым потоком `_reminders_loop`, но выделена отдельно, + чтобы её можно было дёргать напрямую из тестов без запуска потока.""" + now = datetime.now() + now_str = now.strftime("%Y-%m-%d %H:%M:%S") + for r in db.get_due_reminders(now_str): + targets = self._all_admin_ids() if r["recipients"] == "all" else r["recipients"] + body = f"⏰ Напоминание:\n{r['text']}" + for uid in targets: + try: + self.send_message(uid, body) + except Exception as e: + logger.error(f"Не удалось отправить напоминание {r['id']} пользователю {uid}: {e}") + if r["recurrence"] == "once": + db.deactivate_reminder(r["id"]) + else: + anchor = datetime.strptime(r["remind_at"], "%Y-%m-%d %H:%M:%S") + next_dt = compute_next_occurrence(anchor, r["recurrence"], now) + db.update_reminder_next_at(r["id"], next_dt.strftime("%Y-%m-%d %H:%M:%S")) + + def _reminders_loop(self): + """Фоновый цикл: раз в REMINDER_CHECK_INTERVAL_SEC секунд проверяет и шлёт напоминания. + Обрыв на одной итерации (например, сбой отправки) не должен останавливать цикл.""" + while True: + try: + self._check_due_reminders() + except Exception as e: + logger.error(f"Ошибка обработки напоминаний: {e}") + time.sleep(REMINDER_CHECK_INTERVAL_SEC) + def run(self): """Запуск бесконечного цикла прослушивания событий VK LongPoll.""" + threading.Thread(target=self._reminders_loop, daemon=True).start() if not self.longpoll: logger.warning("Бот запущен в режиме ЭМУЛЯЦИИ (без валидных токенов VK API).") print("Симуляция работы бота в консоли. Напишите 'выход' для завершения.")