background task
This commit is contained in:
107
app/scheduler.py
Normal file
107
app/scheduler.py
Normal file
@@ -0,0 +1,107 @@
|
||||
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)}")
|
||||
Reference in New Issue
Block a user