#!/usr/bin/env python3 """ Standalone scheduler service for Workolik daily email reports. This runs independently of the Streamlit application to avoid multiple instances. """ import os import sys import logging from datetime import datetime from zoneinfo import ZoneInfo from apscheduler.schedulers.blocking import BlockingScheduler from apscheduler.triggers.cron import CronTrigger # Add the project root to Python path (scripts/ -> project root) project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if project_root not in sys.path: sys.path.insert(0, project_root) from app_core.services.daily_report import main as run_daily_report # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) def send_daily_report(): """Send the daily report with database-based deduplication using existing email_logs table.""" try: # Check if we already sent today's report today = datetime.now(ZoneInfo('Asia/Kolkata')).date() today_str = today.strftime('%Y-%m-%d') from app_core.db.database import SessionLocal from sqlalchemy import text db = SessionLocal() try: # Check if daily report was already sent today using existing email_logs table # Match the exact subject we generate in daily_report.py ("Daily Digest - YYYY-MM-DD") result = db.execute( text("SELECT id FROM email_logs WHERE date_for = :date_for AND subject = :subject LIMIT 1"), {"date_for": today_str, "subject": f"Daily Digest - {today_str}"} ).fetchone() if result: logger.info(f"Daily report already sent today ({today}), skipping...") return except Exception as e: logger.error(f"Database error checking existing reports: {e}") return finally: db.close() logger.info(f"Starting daily report at {datetime.now(ZoneInfo('Asia/Kolkata'))}") result = run_daily_report() if result == 0: logger.info("Daily report sent successfully") else: logger.warning(f"Daily report failed with exit code: {result}") except Exception as e: logger.error(f"Error sending daily report: {str(e)}") def main(): """Main scheduler function.""" logger.info("Starting Workolik Daily Email Scheduler") # Create scheduler scheduler = BlockingScheduler(timezone=ZoneInfo('Asia/Kolkata')) # Schedule daily email at 8:00 PM IST (20:00) scheduler.add_job( func=send_daily_report, trigger=CronTrigger(hour=20, minute=0, timezone=ZoneInfo('Asia/Kolkata')), id='daily_email_report', name='Daily Email Report', replace_existing=True ) logger.info("Daily email scheduler started - will send reports at 8:00 PM IST") try: # Keep the scheduler running scheduler.start() except KeyboardInterrupt: logger.info("Scheduler stopped by user") scheduler.shutdown() except Exception as e: logger.error(f"Scheduler error: {e}") scheduler.shutdown() if __name__ == "__main__": main()