From ab44f6def686177efb94faff97bfa890078630ac Mon Sep 17 00:00:00 2001 From: Braden Pellett Date: Thu, 31 Jan 2019 16:47:05 -0800 Subject: [PATCH] Remove drift from job scheduling Remove drift from job scheduling, by basing the next run time off the last *scheduled* run time, instead of `datetime.datetime.now()`. Additionally, `idle_seconds` is enforced to be non-negative, since it is now possible for `next_run` to be just before `now()`. --- schedule/__init__.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/schedule/__init__.py b/schedule/__init__.py index 8bca61ac..f643582a 100644 --- a/schedule/__init__.py +++ b/schedule/__init__.py @@ -169,7 +169,8 @@ def idle_seconds(self): :return: Number of seconds until :meth:`next_run `. """ - return (self.next_run - datetime.datetime.now()).total_seconds() + seconds = (self.next_run - datetime.datetime.now()).total_seconds() + return seconds if seconds > 0 else 0 class Job(object): @@ -483,8 +484,10 @@ def run(self): :return: The return value returned by the `job_func` """ logger.debug('Running job %s', self) + self.last_run = ( + self.next_run if self.should_run else datetime.datetime.now() + ) ret = self.job_func() - self.last_run = datetime.datetime.now() self._schedule_next_run() return ret @@ -503,7 +506,13 @@ def _schedule_next_run(self): interval = self.interval self.period = datetime.timedelta(**{self.unit: interval}) - self.next_run = datetime.datetime.now() + self.period + self.next_run = ( + (self.last_run or datetime.datetime.now()) + self.period + ) + # Move the next run to now if it already should have run, in order to + # skip missed jobs. + if self.should_run: + self.next_run = datetime.datetime.now() if self.start_day is not None: if self.unit != 'weeks': raise ScheduleValueError('`unit` should be \'weeks\'')