import asyncio import logging from datetime import datetime from apscheduler.schedulers.background import BackgroundScheduler from app.database import SessionLocal from app.models.reminder import ReminderSchedule from app.models.user import User from app.models.quiz import Quiz logger = logging.getLogger(__name__) scheduler = BackgroundScheduler() def check_and_send_reminders(): """Check for due reminders and send emails.""" db = SessionLocal() try: due_reminders = db.query(ReminderSchedule).filter( ReminderSchedule.is_active == True, ReminderSchedule.next_reminder_at <= datetime.utcnow(), ).all() if not due_reminders: return logger.info(f"Found {len(due_reminders)} due reminders") for reminder in due_reminders: user = db.query(User).filter(User.id == reminder.user_id).first() quiz = db.query(Quiz).filter(Quiz.id == reminder.quiz_id).first() if not user or not quiz: reminder.is_active = False continue # Send email asynchronously try: from app.services.email_service import send_reminder_email loop = asyncio.new_event_loop() loop.run_until_complete( send_reminder_email( email=user.email, user_name=user.name, quiz_title=quiz.title, score=reminder.performance_score, next_date=reminder.next_reminder_at.strftime("%Y-%m-%d"), ) ) loop.close() except Exception as e: logger.error(f"Failed to send reminder {reminder.id}: {e}") # Schedule next reminder from datetime import timedelta reminder.next_reminder_at = datetime.utcnow() + timedelta(days=reminder.interval_days) db.commit() except Exception as e: logger.exception(f"Scheduler error: {e}") finally: db.close() def start_scheduler(): """Start the APScheduler with daily reminder check.""" scheduler.add_job( check_and_send_reminders, "interval", hours=24, id="reminder_check", replace_existing=True, ) scheduler.start() logger.info("Scheduler started — reminder check runs every 24 hours") def stop_scheduler(): if scheduler.running: scheduler.shutdown()