Напоминалки: фоновый планировщик отправки в срок
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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("Симуляция работы бота в консоли. Напишите 'выход' для завершения.")
|
||||
|
||||
Reference in New Issue
Block a user