import asyncio import logging from contextlib import suppress from zoneinfo import ZoneInfo from telegram.ext import Application from .config import REMINDER_POLL_SECONDS from .services import SERVICES_KEY, ApplicationServices from .telegram_utils import escape_markdown_text, markdown_code, send_markdown from .time_utils import format_local_dt, utc_now logger = logging.getLogger(__name__) async def reminder_loop(application: Application) -> None: services: ApplicationServices = application.bot_data[SERVICES_KEY] storage = services.storage tz: ZoneInfo = services.timezone while True: try: due_reminders = storage.due_reminders(utc_now()) for reminder in due_reminders: await send_markdown( application.bot, chat_id=reminder["chat_id"], markdown=( f"**⏰ Напоминание " f"{markdown_code('#' + str(reminder['id']))}**\n\n" f"**Время:** " f"{markdown_code(format_local_dt(reminder['remind_at'], tz))}\n" f"**Задача:** {escape_markdown_text(reminder['text'])}" ), ) storage.mark_reminder_sent(int(reminder["id"])) except asyncio.CancelledError: raise except Exception: logger.exception("Reminder loop failed") await asyncio.sleep(REMINDER_POLL_SECONDS) async def post_init(application: Application) -> None: application.bot_data["reminder_task"] = asyncio.create_task( reminder_loop(application), name="reminder-loop", ) async def post_shutdown(application: Application) -> None: task = application.bot_data.pop("reminder_task", None) if task is None: return task.cancel() with suppress(asyncio.CancelledError): await task