Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Set the daily schedule to a specific time, rather than 24hr from start up #3645

Conversation

boc-the-git
Copy link
Collaborator

@boc-the-git boc-the-git commented May 24, 2024

What type of PR is this?

  • bug

What this PR does / why we need it:

The previous logic for running daily tasks was that at container start it would NOT run, but sleep for 24hrs and then run. For people (like me) who might restart their container daily for backups, or who regularly update their image, this means they effectively never get the daily tasks run.
This change makes it so the daily tasks are scheduled to run at the next 23:45 (or other configured time). Meaning if a container is started at 22:00, it'll run 1:45 later (as opposed to 24:00 later).

This uses changes by @Grygon on #2497 as its basis.

Which issue(s) this PR fixes:

Maybe fixes #3454; it's the reason I noticed this.

Special notes for your reviewer:

Some comments will be added against the code.

Testing

Have done a bit on my prod system.

Realistic case:

mealie  | DEBUG    2024-05-24T20:37:46 - Current time is 2024-05-24 20:37:46.042663 and DAILY_SCHEDULE_TIME is 23:45
mealie  | DEBUG    2024-05-24T20:37:46 - Hours until 3 and minutes until 8
mealie  | INFO     2024-05-24T20:37:46 - Daily tasks scheduled for 2024-05-24 23:45:00

Test case, showing it rolls to next day as needed:

mealie  | DEBUG    2024-05-24T19:47:06 - Current time is 2024-05-24 19:47:06.369710 and target time is 18:45
mealie  | DEBUG    2024-05-24T19:47:06 - Hours until 23 and minutes until 58
mealie  | INFO     2024-05-24T19:47:06 - Daily tasks scheduled for 2024-05-25 19:45:00

Multi day Production run (note changes were implemented at 2024-05-24T20:37:46). This shows that the daily tasks are being run every 23:45 as expected despite, importantly, my container restarting at 1am each day.

mealie  | INFO     2024-05-24T19:30:07 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
mealie  | INFO     2024-05-24T19:45:32 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
mealie  | INFO     2024-05-24T19:47:06 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
mealie  | INFO     2024-05-24T20:07:01 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
mealie  | INFO     2024-05-24T20:17:42 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
mealie  | INFO     2024-05-24T20:37:46 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
mealie  | DEBUG    2024-05-24T23:45:00 - Running daily callbacks
mealie  | INFO     2024-05-25T01:00:14 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
mealie  | DEBUG    2024-05-25T23:45:00 - Running daily callbacks
mealie  | INFO     2024-05-26T01:00:15 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)


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)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linter



@repeat_every(minutes=MINUTES_DAY, wait_first=True, logger=logger)
@repeat_every(minutes=MINUTES_DAY, wait_first=False, logger=logger)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already handle the schedule elsewhere, so we don't want to wait on the first call to run_daily

@boc-the-git boc-the-git marked this pull request as ready for review May 24, 2024 11:28
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)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we sleep to the first scheduled time, which is why we don't want to "wait" on the first run_daily - this is where that happens.

Copy link
Collaborator

@michael-genson michael-genson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Two small changes

str(now),
daily_schedule_time,
)
hour_target = int(daily_schedule_time.split(":")[0])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a try/catch on the daily_schedule_time parsing? Maybe bump it to its own method? That way this doesn't fail if the string is malformed. We could probably default to midnight and log the exception:

try:
    hour_target, minute_target = _parse_daily_schedule_time(daily_schedule_time)
except Exception as e:
    logger.exception(f"Unable to parse {daily_schedule_time=})
    hour_target = minute_target = 0

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. Test:

mealie  | DEBUG    2024-05-26T13:20:41 - Current time is 2024-05-26 13:20:41.016770 and DAILY_SCHEDULE_TIME is ThisIsBadData
mealie  | ERROR    2024-05-26T13:20:41 - Unable to parse daily_schedule_time='ThisIsBadData'
mealie  | Traceback (most recent call last):
mealie  |   File "/app/mealie/services/scheduler/scheduler_service.py", line 39, in schedule_daily
mealie  |     hour_target, minute_target = _parse_daily_schedule_time(daily_schedule_time)
mealie  |   File "/app/mealie/services/scheduler/scheduler_service.py", line 60, in _parse_daily_schedule_time
mealie  |     hour_target = int(time.split(":")[0])
mealie  | ValueError: invalid literal for int() with base 10: 'ThisIsBadData'
mealie  | ERROR    2024-05-26T13:20:41 - Unable to parse daily_schedule_time='ThisIsBadData'
mealie  | Traceback (most recent call last):
mealie  |   File "/app/mealie/services/scheduler/scheduler_service.py", line 39, in schedule_daily
mealie  |     hour_target, minute_target = _parse_daily_schedule_time(daily_schedule_time)
mealie  |   File "/app/mealie/services/scheduler/scheduler_service.py", line 60, in _parse_daily_schedule_time
mealie  |     hour_target = int(time.split(":")[0])
mealie  | ValueError: invalid literal for int() with base 10: 'ThisIsBadData'
mealie  | DEBUG    2024-05-26T13:20:41 - Hours until 10 and minutes until 25
mealie  | INFO     2024-05-26T13:20:41 - Daily tasks scheduled for 2024-05-26 23:45:00
mealie  | INFO     2024-05-26T13:20:41 - Application startup complete.
mealie  | INFO     2024-05-26T13:20:41 - Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)

@@ -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. |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extend the last pipe out so it lines up? Just for my own sanity, I don't think it actually matters

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not try to be pedantic about this .. that whole table structure is a bit of a mess, and any change made to try and fix it now will just get "broken" in future. There's a ton of inconsistency in there already.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, maybe it's just GitHub then, it seems to be formatted correctly to me:

image

But whatever it really doesn't matter anyway

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, you're correct. VSCode was completely distorting it for me 🤦

Fixed.

Copy link
Collaborator

@michael-genson michael-genson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@michael-genson michael-genson enabled auto-merge (squash) May 26, 2024 03:54
@michael-genson michael-genson merged commit e07467d into mealie-recipes:mealie-next May 26, 2024
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] - Recipe timeline event is not created automatically after recipe was added to the meal planner
2 participants