Bot & Automation

Activity Reminder Bot

/root/hermes-projects/Activity Reminder Bot

apps/activity_reminder_bot/scheduler/reminder_scheduler.py text
import logging

from aiogram import Bot
from apscheduler.schedulers.asyncio import AsyncIOScheduler

from activity_reminder_bot.bot.keyboards import alarm_action_keyboard
from activity_reminder_bot.core.config import get_settings
from activity_reminder_bot.services.formatters import format_alarm
from activity_reminder_bot.services.reminders import ReminderService

logger = logging.getLogger(__name__)


class ReminderScheduler:
    def __init__(self, bot: Bot, service: ReminderService | None = None) -> None:
        self.bot = bot
        self.service = service or ReminderService()
        self.settings = get_settings()
        self.scheduler = AsyncIOScheduler(timezone=self.settings.timezone)

    async def start(self) -> None:
        self.scheduler.add_job(
            self.scan_due_reminders,
            trigger="interval",
            seconds=self.settings.scheduler_scan_seconds,
            id="scan_due_reminders",
            replace_existing=True,
            max_instances=1,
            coalesce=True,
        )
        self.scheduler.start()
        logger.info("Reminder scheduler started")

    async def shutdown(self) -> None:
        self.scheduler.shutdown(wait=False)

    async def scan_due_reminders(self) -> None:
        if not self.service.is_configured():
            logger.warning("Google Sheets is not configured; scheduler scan skipped")
            return
        due_reminders = await self.service.due_reminders()
        now = self.service.now()
        for reminder in due_reminders:
            try:
                sent_message = await self.bot.send_message(
                    chat_id=reminder.user_id,
                    text=format_alarm(reminder, now),
                    reply_markup=alarm_action_keyboard(reminder.public_id),
                    disable_notification=False,
                )
                if (
                    self.settings.alarm_delete_previous_message
                    and reminder.alarm_message_id
                    and reminder.alarm_message_id != sent_message.message_id
                ):
                    try:
                        await self.bot.delete_message(
                            chat_id=reminder.user_id,
                            message_id=reminder.alarm_message_id,
                        )
                    except Exception as exc:
                        logger.warning(
                            "Failed to delete previous alarm message %s for reminder %s: %s",
                            reminder.alarm_message_id,
                            reminder.public_id,
                            exc,
                        )
                await self.service.mark_notified(reminder, sent_message.message_id)
            except Exception as exc:
                logger.exception("Failed to send reminder %s: %s", reminder.public_id, exc)