-
Notifications
You must be signed in to change notification settings - Fork 3.7k
AAP-70288 Catch errors on re-compute of schedule RRULE computed fields #16400
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
base: devel
Are you sure you want to change the base?
Changes from all commits
36ba8a6
24a4f99
75c9dbb
27164f0
719aeff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -174,7 +174,11 @@ def get_zoneinfo_links(cls): | |
| def timezone(self): | ||
| utc = tzutc() | ||
| # All rules in a ruleset will have the same dtstart so we can just take the first rule | ||
| tzinfo = Schedule.rrulestr(self.rrule)._rrule[0]._dtstart.tzinfo | ||
| try: | ||
| tzinfo = Schedule.rrulestr(self.rrule)._rrule[0]._dtstart.tzinfo | ||
| except ValueError as e: | ||
| logger.warning("Schedule id=%s has an invalid rrule, cannot determine timezone: %s", self.id, e) | ||
| return '' | ||
| if tzinfo is utc: | ||
| return 'UTC' | ||
| all_zones = Schedule.get_zoneinfo() | ||
|
|
@@ -192,7 +196,12 @@ def timezone(self): | |
| def until(self): | ||
| # The UNTIL= datestamp (if any) coerced from UTC to the local naive time | ||
| # of the DTSTART | ||
| for r in Schedule.rrulestr(self.rrule)._rrule: | ||
| try: | ||
| rrules = Schedule.rrulestr(self.rrule)._rrule | ||
| except ValueError as e: | ||
| logger.warning("Schedule id=%s has an invalid rrule, cannot determine until: %s", self.id, e) | ||
| return '' | ||
| for r in rrules: | ||
| if r._until: | ||
| local_until = r._until.astimezone(r._dtstart.tzinfo) | ||
| naive_until = local_until.replace(tzinfo=None) | ||
|
|
@@ -317,7 +326,16 @@ def update_computed_fields_no_save(self): | |
| for field_name in affects_fields: | ||
| starting_values[field_name] = getattr(self, field_name) | ||
|
|
||
| future_rs = Schedule.rrulestr(self.rrule) | ||
| try: | ||
| future_rs = Schedule.rrulestr(self.rrule) | ||
| except ValueError as e: | ||
| logger.error( | ||
| "Schedule id=%s has an invalid rrule that cannot be parsed: %s. Error: %s", | ||
| self.id, | ||
| self.rrule, | ||
| e, | ||
| ) | ||
| raise | ||
|
Comment on lines
+329
to
+338
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Persisted-state gap: At Line 340, re-raising exits before any save, so scheduler catch-and-continue paths can leave stale DB values and repeatedly re-select the same broken schedule. Proposed fix def update_computed_fields(self):
- changed = self.update_computed_fields_no_save()
+ try:
+ changed = self.update_computed_fields_no_save()
+ except ValueError:
+ # Fields were nulled in update_computed_fields_no_save(); persist that state.
+ super(Schedule, self).save(update_fields=['next_run', 'dtend', 'modified'])
+ raise
if not changed:
return
emit_channel_notification('schedules-changed', dict(id=self.id, group_name='schedules'))As per coding guidelines, "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity." 🤖 Prompt for AI Agents
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...seems valid, unfortunately. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Failed to handle agent chat message. Please try again.
cursor[bot] marked this conversation as resolved.
|
||
|
|
||
| if self.enabled: | ||
| next_run_actual = future_rs.after(now()) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing root-cause catch permanently disables valid schedules
High Severity
The PR description states the fix "catches
ValueErrorin_fast_forward_rruleand falls back to the original rrule," but_fast_forward_rrulehas no such catch aroundrrule.replace()at line 100. Without it, theValueErrorpropagates to the new handlers inawx_periodic_scheduler, which setnext_run=Nonevia direct DB update. Sincenext_run=Nonenever matches thebefore()orbetween()query filters, the schedule is permanently disabled — even after DST ends and the fast-forward would succeed again. Because fast-forwarding is purely a performance optimization, catchingValueErrorin_fast_forward_rruleand returning the original rrule would let valid schedules keep running instead of being irreversibly killed.Additional Locations (2)
awx/main/tasks/system.py#L883-L888awx/main/tasks/system.py#L898-L904Reviewed by Cursor Bugbot for commit 719aeff. Configure here.