98 lines
3.3 KiB
Python
98 lines
3.3 KiB
Python
#!/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()
|