Coverage for opt/mealie/lib/python3.12/site-packages/mealie/services/scheduler/scheduler_service.py: 86%
56 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 03:04 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 03:04 +0000
1import asyncio
2from datetime import UTC, datetime, timedelta
3from pathlib import Path
5from mealie.core import root_logger
6from mealie.core.config import get_app_settings
7from mealie.services.scheduler.runner import repeat_every
9from .scheduler_registry import SchedulerRegistry
11logger = root_logger.get_logger()
13CWD = Path(__file__).parent
15MINUTES_DAY = 1440
16MINUTES_5 = 5
17MINUTES_HOUR = 60
20class SchedulerService:
21 @staticmethod
22 async def start():
23 await run_minutely()
24 await run_hourly()
26 # Wait to trigger our daily run until our given "daily time", so having asyncio handle it.
27 asyncio.create_task(schedule_daily())
30async def schedule_daily():
31 now = datetime.now(UTC)
32 daily_schedule_time = get_app_settings().DAILY_SCHEDULE_TIME_UTC
33 logger.debug(f"Current time is {now} and DAILY_SCHEDULE_TIME (in UTC) is {daily_schedule_time}")
35 next_schedule = now.replace(
36 hour=daily_schedule_time.hour, minute=daily_schedule_time.minute, second=0, microsecond=0
37 )
38 delta = next_schedule - now
39 if delta < timedelta(0): 39 ↛ 40line 39 didn't jump to line 40 because the condition on line 39 was never true
40 next_schedule = next_schedule + timedelta(days=1)
41 delta = next_schedule - now
43 hours_until, seconds_reminder = divmod(delta.total_seconds(), 3600)
44 minutes_until, seconds_reminder = divmod(seconds_reminder, 60)
45 seconds_until = round(seconds_reminder)
46 logger.debug("Time left: %02d:%02d:%02d", hours_until, minutes_until, seconds_until)
48 target_time = next_schedule.replace(microsecond=0, second=0)
49 logger.info("Daily tasks scheduled for %s", str(target_time))
51 wait_seconds = delta.total_seconds()
52 await asyncio.sleep(wait_seconds)
53 await run_daily()
56def _scheduled_task_wrapper(callable):
57 try:
58 callable()
59 except Exception as e:
60 logger.error("Error in scheduled task func='%s': exception='%s'", callable.__name__, e)
63@repeat_every(minutes=MINUTES_DAY, wait_first=False, logger=logger)
64def run_daily():
65 logger.debug("Running daily callbacks")
66 for func in SchedulerRegistry._daily:
67 _scheduled_task_wrapper(func)
70@repeat_every(minutes=MINUTES_HOUR, wait_first=True, logger=logger)
71def run_hourly():
72 logger.debug("Running hourly callbacks")
73 for func in SchedulerRegistry._hourly:
74 _scheduled_task_wrapper(func)
77@repeat_every(minutes=MINUTES_5, wait_first=True, logger=logger)
78def run_minutely():
79 logger.debug("Running minutely callbacks")
80 for func in SchedulerRegistry._minutely:
81 _scheduled_task_wrapper(func)