Initial commit
This commit is contained in:
97
scripts/scheduler_standalone.py
Normal file
97
scripts/scheduler_standalone.py
Normal file
@@ -0,0 +1,97 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user