import logging import time from datetime import datetime, timedelta from threading import Thread from app.models import User from app.email_processor import EmailProcessor from app import create_app class Scheduler: """ Background scheduler for email processing tasks. Runs as a separate thread to process emails at regular intervals. """ def __init__(self, app=None, interval_minutes=5): self.app = app self.interval = interval_minutes * 60 # Convert to seconds self.thread = None self.running = False self.logger = logging.getLogger(__name__) if app: self.init_app(app) def init_app(self, app): """Initialize the scheduler with a Flask application.""" self.app = app # Store scheduler in app extensions if not hasattr(app, 'extensions'): app.extensions = {} app.extensions['scheduler'] = self def start(self): """Start the background scheduler thread.""" if self.running: self.logger.warning("Scheduler is already running") return self.running = True self.thread = Thread(target=self._run, daemon=True) self.thread.start() self.logger.info(f"Scheduler started with {self.interval//60} minute interval") def stop(self): """Stop the background scheduler.""" self.running = False if self.thread: self.logger.info("Scheduler stopped") self.thread.join() def _run(self): """Main loop for the scheduler.""" # Wait a moment before first run to allow app to start time.sleep(5) while self.running: try: self.logger.info("Starting scheduled email processing") self.process_all_users() # Calculate next run time next_run = datetime.now() + timedelta(seconds=self.interval) self.logger.info(f"Next run at {next_run.strftime('%Y-%m-%d %H:%M:%S')}") # Sleep for the interval, checking every 10 seconds if we should stop slept = 0 while self.running and slept < self.interval: sleep_time = min(10, self.interval - slept) time.sleep(sleep_time) slept += sleep_time except Exception as e: self.logger.error(f"Error in scheduler: {str(e)}") # Continue running even if there's an error continue def process_all_users(self): """Process emails for all users.""" with self.app.app_context(): try: # Get all users users = User.query.all() if not users: self.logger.info("No users found for processing") return self.logger.info(f"Processing emails for {len(users)} users") # Process each user's emails for user in users: try: processor = EmailProcessor(user) result = processor.process_user_emails() self.logger.info(f"Completed processing for user {user.email}: " f"{result['success_count']} success, " f"{result['error_count']} errors, " f"{len(result['processed_folders'])} folders processed") except Exception as e: self.logger.error(f"Error processing emails for user {user.email}: {str(e)}") continue except Exception as e: self.logger.error(f"Error in process_all_users: {str(e)}")