mirror of
https://github.com/ansible/awx.git
synced 2026-03-26 13:25:02 -02:30
More precise handling of schedule computed fields no-ops
Do not set a next_run value for disabled schedules Bail if no fields are changed Do not update related template if its fields did not change Change call pattern to schedule.update_computed_fields() in doing so, fix bug where template does not pick up schedule due to schedules next_run not being saved Handle the case (also a bug) where template was not updated when schedule was deleted
This commit is contained in:
@@ -227,15 +227,23 @@ class Schedule(PrimordialModel, LaunchTimeConfig):
|
||||
job_kwargs['_eager_fields'] = {'launch_type': 'scheduled', 'schedule': self}
|
||||
return job_kwargs
|
||||
|
||||
def update_computed_fields(self):
|
||||
future_rs = Schedule.rrulestr(self.rrule)
|
||||
next_run_actual = future_rs.after(now())
|
||||
def update_computed_fields_no_save(self):
|
||||
affects_fields = ['next_run', 'dtstart', 'dtend']
|
||||
starting_values = {}
|
||||
for field_name in affects_fields:
|
||||
starting_values[field_name] = getattr(self, field_name)
|
||||
|
||||
if next_run_actual is not None:
|
||||
if not datetime_exists(next_run_actual):
|
||||
# skip imaginary dates, like 2:30 on DST boundaries
|
||||
next_run_actual = future_rs.after(next_run_actual)
|
||||
next_run_actual = next_run_actual.astimezone(pytz.utc)
|
||||
future_rs = Schedule.rrulestr(self.rrule)
|
||||
|
||||
if self.enabled:
|
||||
next_run_actual = future_rs.after(now())
|
||||
if next_run_actual is not None:
|
||||
if not datetime_exists(next_run_actual):
|
||||
# skip imaginary dates, like 2:30 on DST boundaries
|
||||
next_run_actual = future_rs.after(next_run_actual)
|
||||
next_run_actual = next_run_actual.astimezone(pytz.utc)
|
||||
else:
|
||||
next_run_actual = None
|
||||
|
||||
self.next_run = next_run_actual
|
||||
try:
|
||||
@@ -248,11 +256,38 @@ class Schedule(PrimordialModel, LaunchTimeConfig):
|
||||
self.dtend = future_rs[-1].astimezone(pytz.utc)
|
||||
except IndexError:
|
||||
self.dtend = None
|
||||
|
||||
changed = any(getattr(self, field_name) != starting_values[field_name] for field_name in affects_fields)
|
||||
return changed
|
||||
|
||||
def update_computed_fields(self):
|
||||
changed = self.update_computed_fields_no_save()
|
||||
if not changed:
|
||||
return
|
||||
emit_channel_notification('schedules-changed', dict(id=self.id, group_name='schedules'))
|
||||
# Must save self here before calling unified_job_template computed fields
|
||||
# in order for that method to be correct
|
||||
# by adding modified to update fields, we avoid updating modified time
|
||||
super(Schedule, self).save(update_fields=['next_run', 'dtstart', 'dtend', 'modified'])
|
||||
with ignore_inventory_computed_fields():
|
||||
self.unified_job_template.update_computed_fields()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.update_computed_fields()
|
||||
self.rrule = Schedule.coerce_naive_until(self.rrule)
|
||||
changed = self.update_computed_fields_no_save()
|
||||
if changed and 'update_fields' in kwargs:
|
||||
for field_name in ['next_run', 'dtstart', 'dtend']:
|
||||
if field_name not in kwargs['update_fields']:
|
||||
kwargs['update_fields'].append(field_name)
|
||||
super(Schedule, self).save(*args, **kwargs)
|
||||
if changed:
|
||||
with ignore_inventory_computed_fields():
|
||||
self.unified_job_template.update_computed_fields()
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
ujt = self.unified_job_template
|
||||
r = super(Schedule, self).delete(*args, **kwargs)
|
||||
if ujt:
|
||||
with ignore_inventory_computed_fields():
|
||||
ujt.update_computed_fields()
|
||||
return r
|
||||
|
||||
@@ -253,11 +253,13 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio
|
||||
return self.last_job_run
|
||||
|
||||
def update_computed_fields(self):
|
||||
Schedule = self._meta.get_field('schedules').related_model
|
||||
related_schedules = Schedule.objects.filter(enabled=True, unified_job_template=self, next_run__isnull=False).order_by('-next_run')
|
||||
if related_schedules.exists():
|
||||
self.next_schedule = related_schedules[0]
|
||||
self.next_job_run = related_schedules[0].next_run
|
||||
related_schedules = self.schedules.filter(enabled=True, next_run__isnull=False).order_by('-next_run')
|
||||
new_next_schedule = related_schedules.first()
|
||||
if new_next_schedule:
|
||||
if new_next_schedule.pk == self.next_schedule_id and new_next_schedule.next_run == self.next_job_run:
|
||||
return # no-op, common for infrequent schedules
|
||||
self.next_schedule = new_next_schedule
|
||||
self.next_job_run = new_next_schedule.next_run
|
||||
self.save(update_fields=['next_schedule', 'next_job_run'])
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
||||
Reference in New Issue
Block a user