def upcoming(self, include_overdue=False): """Return Schedules that will be coming due in the future. Optionally include test lists that are currently due and overdue""" start, end = today_start_end() end = end + timezone.timedelta(days=self.future_days) schedules = self.schedules().filter(due_date__lte=end) if not include_overdue: schedules = schedules.filter(due_date__gte=start) return schedules
def test_due_and_overdue(self): start, end = today_start_end() self.utc1.due_date = start + timezone.timedelta(hours=12) self.utc1.save() self.utc2.due_date = timezone.now() - timezone.timedelta(hours=2 * 24) self.utc2.save() notice = QCSchedulingNotice.objects.create( recipients=self.recipients, notification_type=QCSchedulingNotice.DUE, time="0:00", ) assert list(notice.utcs_to_notify()) == [self.utc1, self.utc2]
def test_due(self): start, end = today_start_end() self.sch1.due_date = start + timezone.timedelta(hours=12) self.sch1.save() self.sch2.due_date = timezone.now() + timezone.timedelta(hours=2 * 24) self.sch2.save() notice = ServiceEventSchedulingNotice.objects.create( recipients=self.recipients, notification_type=ServiceEventSchedulingNotice.DUE, time="0:00", ) assert list(notice.schedules_to_notify()) == [self.sch1]
def test_upcoming_and_overdue(self): start, end = today_start_end() self.sch1.due_date = start + timezone.timedelta(hours=36) self.sch1.save() self.sch2.due_date = timezone.now() - timezone.timedelta(hours=2 * 24) self.sch2.save() notice = ServiceEventSchedulingNotice.objects.create( recipients=self.recipients, notification_type=ServiceEventSchedulingNotice.UPCOMING_AND_DUE, future_days=7, time="0:00", ) assert list(notice.schedules_to_notify()) == [self.sch1, self.sch2]
def run_periodic_scheduler(model, log_name, handler, time_field="time", recurrence_field="recurrence"): """Check a model with a recurring schedule for instances that should be run in the next time period. model: the Django model to check, log_name: short description to include in log strings, handler: a function that will be called when an instance should be run in the current time period must accept an instance of model, and a datetime when the task should be scheduled for. The handler function should perform the actual scheduling of the task. time_field: The name of the field that holds what time the task should be run recurrence_field: The name of the field that holds the recurrence field """ start_today, end_today = today_start_end() start_today = start_today.replace(tzinfo=None) end_today = end_today.replace(tzinfo=None) now = timezone.localtime(timezone.now()).replace(tzinfo=None) start_time, end_time = (now, now + timezone.timedelta(minutes=15)) logger.info("Running %s task at %s for notices between %s and %s" % (log_name, now, start_time, end_time)) # first narrow down notices to those supposed to run in this 15 minute block instances = model.objects.filter( **{ "%s__gte" % time_field: start_time.strftime("%H:%M"), "%s__lte" % time_field: end_time.strftime("%H:%M"), }) if settings.DEBUG: # pragma: nocover instances = model.objects.all() # now look at recurrences occuring today and see if they should be sent now for instance in instances: # since our recurrence can only occur with a maximum frequency of 1 / # day, between will just return ~timezone.now() if the report is to be # sent today. If we make reports available at a higher frequency this # check will need to be adjusted. occurences = getattr(instance, recurrence_field).between(start_today, end_today) logger.info("Occurences for %s %s: %s (between %s & %s)" % ( model._meta.model_name, instance.id, occurences, start_today, end_today, )) if occurences and start_time.time() <= getattr( instance, time_field) <= end_time.time(): tz = timezone.get_current_timezone() send_time = tz.localize( timezone.datetime.combine(start_today, getattr(instance, time_field))) handler(instance, send_time)
def due_and_overdue(self): """Return Schedules that are currently due or overdue""" start, end = today_start_end() return self.schedules().filter(due_date__lte=end)