mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-27 00:04:23 -04:00 
			
		
		
		
	fix: Set the daily schedule to a specific time, rather than 24hr from start up (#3645)
This commit is contained in:
		| @@ -16,7 +16,8 @@ | ||||
| | TZ                            |          UTC          | Must be set to get correct date/time on the server                                  | | ||||
| | ALLOW_SIGNUP<super>\*</super> |         false         | Allow user sign-up without token                                                    | | ||||
| | LOG_CONFIG_OVERRIDE           |                       | Override the config for logging with a custom path                                  | | ||||
| | LOG_LEVEL                     |         info          | logging level configured                                                            | | ||||
| | LOG_LEVEL                     |         info          | Logging level configured                                                            | | ||||
| | DAILY_SCHEDULE_TIME           |        23:45          | The time of day to run the daily tasks.                                             | | ||||
|  | ||||
| <super>\*</super> Starting in v1.4.0 this was changed to default to `false` as apart of a security review of the application. | ||||
|  | ||||
|   | ||||
| @@ -57,6 +57,8 @@ class AppSettings(BaseSettings): | ||||
|  | ||||
|     ALLOW_SIGNUP: bool = False | ||||
|  | ||||
|     DAILY_SCHEDULE_TIME: str = "23:45" | ||||
|  | ||||
|     # =============================================== | ||||
|     # Security Configuration | ||||
|  | ||||
| @@ -199,7 +201,11 @@ class AppSettings(BaseSettings): | ||||
|     def OIDC_READY(self) -> bool: | ||||
|         """Validates OIDC settings are all set""" | ||||
|  | ||||
|         required = {self.OIDC_CLIENT_ID, self.OIDC_CONFIGURATION_URL, self.OIDC_USER_CLAIM} | ||||
|         required = { | ||||
|             self.OIDC_CLIENT_ID, | ||||
|             self.OIDC_CONFIGURATION_URL, | ||||
|             self.OIDC_USER_CLAIM, | ||||
|         } | ||||
|         not_none = None not in required | ||||
|         valid_group_claim = True | ||||
|         if (not self.OIDC_USER_GROUP or not self.OIDC_ADMIN_GROUP) and not self.OIDC_GROUPS_CLAIM: | ||||
|   | ||||
| @@ -1,6 +1,9 @@ | ||||
| import asyncio | ||||
| from datetime import datetime, timedelta | ||||
| from pathlib import Path | ||||
|  | ||||
| from mealie.core import root_logger | ||||
| from mealie.core.config import get_app_settings | ||||
| from mealie.services.scheduler.runner import repeat_every | ||||
|  | ||||
| from .scheduler_registry import SchedulerRegistry | ||||
| @@ -18,18 +21,53 @@ class SchedulerService: | ||||
|     @staticmethod | ||||
|     async def start(): | ||||
|         await run_minutely() | ||||
|         await run_daily() | ||||
|         await run_hourly() | ||||
|  | ||||
|         # Wait to trigger our daily run until our given "daily time", so having asyncio handle it. | ||||
|         asyncio.create_task(schedule_daily()) | ||||
|  | ||||
|  | ||||
| async def schedule_daily(): | ||||
|     now = datetime.now() | ||||
|     daily_schedule_time = get_app_settings().DAILY_SCHEDULE_TIME | ||||
|     logger.debug( | ||||
|         "Current time is %s and DAILY_SCHEDULE_TIME is %s", | ||||
|         str(now), | ||||
|         daily_schedule_time, | ||||
|     ) | ||||
|     try: | ||||
|         hour_target, minute_target = _parse_daily_schedule_time(daily_schedule_time) | ||||
|     except Exception: | ||||
|         logger.exception(f"Unable to parse {daily_schedule_time=}") | ||||
|         hour_target = 23 | ||||
|         minute_target = 45 | ||||
|  | ||||
|     hours_until = ((hour_target - now.hour) % 24) or 24 | ||||
|     minutes_until = (minute_target - now.minute) % 60 | ||||
|     logger.debug("Hours until %s and minutes until %s", str(hours_until), str(minutes_until)) | ||||
|  | ||||
|     delta = timedelta(hours=hours_until, minutes=minutes_until) | ||||
|     target_time = (now + delta).replace(microsecond=0, second=0) | ||||
|     logger.info("Daily tasks scheduled for %s", str(target_time)) | ||||
|     wait_seconds = (target_time - now).total_seconds() | ||||
|     await asyncio.sleep(wait_seconds) | ||||
|     await run_daily() | ||||
|  | ||||
|  | ||||
| def _parse_daily_schedule_time(time): | ||||
|     hour_target = int(time.split(":")[0]) | ||||
|     minute_target = int(time.split(":")[1]) | ||||
|     return hour_target, minute_target | ||||
|  | ||||
|  | ||||
| def _scheduled_task_wrapper(callable): | ||||
|     try: | ||||
|         callable() | ||||
|     except Exception as e: | ||||
|         logger.error(f"Error in scheduled task func='{callable.__name__}': exception='{e}'") | ||||
|         logger.error("Error in scheduled task func='%s': exception='%s'", callable.__name__, e) | ||||
|  | ||||
|  | ||||
| @repeat_every(minutes=MINUTES_DAY, wait_first=True, logger=logger) | ||||
| @repeat_every(minutes=MINUTES_DAY, wait_first=False, logger=logger) | ||||
| def run_daily(): | ||||
|     logger.debug("Running daily callbacks") | ||||
|     for func in SchedulerRegistry._daily: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user