""" APScheduler entry point for the scheduler container. Run: python -m app.scheduler Weekly cadence (America/Los_Angeles): Fri 02:00 — scrape (Lucky weekend prices live by ~midnight) Fri 05:00 — generate (fresh grocery data) Fri 06:00 — email (per-voter approval links) Fri 17:00 — deadline (pending items resolved per family policy) Fri 18:00 — finalize (shopping-list email) """ import logging from apscheduler.schedulers.blocking import BlockingScheduler from apscheduler.triggers.cron import CronTrigger from app.services.orchestrator.runner import run_step logging.basicConfig( level="INFO", format="%(asctime)s %(levelname)s %(name)s %(message)s", ) logger = logging.getLogger(__name__) TZ = "America/Los_Angeles" scheduler = BlockingScheduler(timezone=TZ) scheduler.add_job( lambda: run_step("scrape"), CronTrigger(day_of_week="fri", hour=2, minute=0, timezone=TZ), id="weekly_scrape", name="Weekly scrape (Fri 02:00 PT)", ) scheduler.add_job( lambda: run_step("generate"), CronTrigger(day_of_week="fri", hour=5, minute=0, timezone=TZ), id="weekly_generate", name="Weekly generate (Fri 05:00 PT)", ) scheduler.add_job( lambda: run_step("email"), CronTrigger(day_of_week="fri", hour=6, minute=0, timezone=TZ), id="weekly_email", name="Weekly email (Fri 06:00 PT)", ) scheduler.add_job( lambda: run_step("deadline"), CronTrigger(day_of_week="fri", hour=17, minute=0, timezone=TZ), id="weekly_deadline", name="Weekly deadline (Fri 17:00 PT)", ) scheduler.add_job( lambda: run_step("finalize"), CronTrigger(day_of_week="fri", hour=18, minute=0, timezone=TZ), id="weekly_finalize", name="Weekly finalize (Fri 18:00 PT)", ) if __name__ == "__main__": logger.info("Starting MealPlanner scheduler (tz=%s)", TZ) for job in scheduler.get_jobs(): logger.info(" Registered: %s", job.name) try: scheduler.start() except (KeyboardInterrupt, SystemExit): logger.info("Scheduler stopped")