import logging from datetime import datetime, timezone from sqlalchemy import select from sqlalchemy.orm import Session from app.db.models import Reminder, User from app.reminders.completion import ReminderCompletionHandler from app.reminders.notify import bump_notify_seq logger = logging.getLogger(__name__) def _utcnow() -> datetime: return datetime.now(timezone.utc) def get_due_reminders(db: Session, user_id: int) -> list[Reminder]: now = _utcnow() stmt = ( select(Reminder) .where( Reminder.user_id == user_id, Reminder.enabled.is_(True), Reminder.completed_at.is_(None), Reminder.due_at <= now, ) .order_by(Reminder.due_at.asc()) ) rows = list(db.scalars(stmt).all()) return [row for row in rows if not (row.last_fired_at and row.last_fired_at >= row.due_at)] async def process_due_reminders(db: Session) -> int: users = db.scalars(select(User).where(User.is_active.is_(True))).all() total = 0 for user in users: due = get_due_reminders(db, user.id) if not due: continue handler = ReminderCompletionHandler(db, user.id) for row in due: await handler.process(row) total += len(due) if total: db.commit() bump_notify_seq(db) logger.info("Reminders fired: %d", total) return total