def get_next_trigger_time(self, previous_trigger_time, now=None): if not now: curr_time = datetime.now(self.timezone) else: curr_time = now if previous_trigger_time: next_trigger_time = previous_trigger_time + self.interval elif self.start_date > curr_time: next_trigger_time = self.start_date else: timediff_seconds = timedelta_seconds(curr_time - self.start_date) next_interval_num = int(ceil(timediff_seconds / self.interval_length)) next_trigger_time = self.start_date + self.interval * next_interval_num if not self.end_date or next_trigger_time <= self.end_date: return self.timezone.normalize(next_trigger_time)
def __init__(self, weeks=0, days=0, hours=0, minutes=0, seconds=0, start_date=None, end_date=None, timezone=None): if timezone: timezone = astimezone(timezone) elif start_date and start_date.tzinfo: timezone = start_date.tzinfo elif end_date and end_date.tzinfo: timezone = end_date.tzinfo else: timezone = get_localzone() BaseTrigger.__init__(self, timezone) self.interval = timedelta(weeks=weeks, days=days, hours=hours, minutes=minutes, seconds=seconds) self.interval_length = timedelta_seconds(self.interval) if self.interval_length == 0: self.interval = timedelta(seconds=1) self.interval_length = 1 start_date = start_date or (datetime.now(self.timezone) + self.interval) self.start_date = convert_to_datetime(start_date, self.timezone, 'start_date') self.end_date = convert_to_datetime(end_date, self.timezone, 'end_date')
def start(self): """ Start elric master. Select all due jobs from jobstore and enqueue them into redis queue. Then update due jobs' information into jobstore. :return: """ if self.running: raise AlreadyRunningException self._stopped = False self.log.debug('eric master start...') while True: now = datetime.now(self.timezone) wait_seconds = None with self.jobstore_lock: for job_id, job_key, serialized_job in self.jobstore.get_due_jobs(now): # enqueue due job into redis queue self._enqueue_job(job_key, serialized_job) # update job's information, such as next_run_time job_in_dict = Job.deserialize_to_dict(serialized_job) last_run_time = Job.get_serial_run_times(job_in_dict, now) if last_run_time: next_run_time = Job.get_next_trigger_time(job_in_dict, last_run_time[-1]) if next_run_time: job_in_dict['next_run_time'] = next_run_time self.update_job(job_id, job_key, next_run_time, Job.dict_to_serialization(job_in_dict)) else: # if job has no next run time, then remove it from jobstore self.remove_job(job_id=job_id) # get next closet run time job from jobstore and set it to be wake up time closest_run_time = self.jobstore.get_closest_run_time() if closest_run_time is not None: wait_seconds = max(timedelta_seconds(closest_run_time - now), 0) self.log.debug('Next wakeup is due at %s (in %f seconds)' % (closest_run_time, wait_seconds)) self._event.wait(wait_seconds if wait_seconds is not None else self.MAX_WAIT_TIME) self._event.clear()