-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
feat(aci): enforce workflow frequency when firing actions #83160
base: master
Are you sure you want to change the base?
Conversation
# TODO(cathy): only reinforce workflow frequency for certain issue types | ||
now = timezone.now() | ||
|
||
statuses = ActionGroupStatus.objects.filter(group=group, action__in=actions) |
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.
debating whether to add select_related here, i think it would make the annotation more performant? but is it going across too many FKs and/or there won't be too many objects here?
.select_related("action__dataconditiongroupaction__condition_group__workflowdataconditiongroup__workflow__config")
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.
i think given that we only need the 1 field, and how the number of joins that it will be pretty even on the performance. in general, select_related is more performant unless the tables are huge and you want multiple properties.
ActionGroupStatus.objects.filter(action__in=actions_to_include, group=group).update( | ||
date_updated=now | ||
) | ||
ActionGroupStatus.objects.bulk_create( | ||
[ | ||
ActionGroupStatus(action=action, group=group, date_updated=now) | ||
for action in actions_without_statuses | ||
], | ||
batch_size=1000, | ||
) |
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.
i think bulk updating here would be better than in each action individually
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.
generally lgtm, i think my biggest question is if we could utilize the base query set being passed into the filter_recently_fired_workflow_actions
method at the end to get the filtered actions instead?
statuses = statuses.annotate( | ||
frequency=Cast( | ||
Coalesce( | ||
KeyTextTransform( | ||
"frequency", | ||
F( | ||
"action__dataconditiongroupaction__condition_group__workflowdataconditiongroup__workflow__config" | ||
), | ||
), | ||
Value("30"), # default 30 | ||
), | ||
output_field=IntegerField(), | ||
), | ||
frequency_seconds=ExpressionWrapper( | ||
F("frequency") * timedelta(minutes=1), # convert to timedelta | ||
output_field=DurationField(), | ||
), | ||
difference=ExpressionWrapper( | ||
Value(now) - F("date_updated"), output_field=DurationField() | ||
), # how long ago the action fired | ||
) |
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.
mind decomposing this a little? it could be nice to just set a few vars for each of the kwargs.
Maybe something along these lines:
workflow_config_path = F("action__dataconditiongroupaction__condition_group__workflowdataconditiongroup__workflow__config")
check_frequency_minutes = Cast(
Coalesce(
KeyTextTransform("frequency", workflow_config_path),
Value("30")
),
output_field=IntegerField()
)
check_interval = ExpressionWrapper(
F("frequency") * timedelta(minutes=1),
output_field=DurationField()
)
time_since_last_update = ExpressionWrapper(
Value(current_time) - F("date_updated"),
output_field=DurationField()
)
return statuses.annotate(
frequency=check_frequency_minutes,
frequency_seconds=check_interval,
difference=time_since_last_update
)
🤔 should this be it's own method?
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.
i moved it into its own method 👍
# TODO(cathy): only reinforce workflow frequency for certain issue types | ||
now = timezone.now() | ||
|
||
statuses = ActionGroupStatus.objects.filter(group=group, action__in=actions) |
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.
i think given that we only need the 1 field, and how the number of joins that it will be pretty even on the performance. in general, select_related is more performant unless the tables are huge and you want multiple properties.
) | ||
|
||
actions_without_statuses_ids = {action.id for action in actions_without_statuses} | ||
filtered_actions = Action.objects.filter( |
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.
do we need to make another query to the action table or could we apply filters to the action query set that's being passed into this method?
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.
updated!
cbeb55d
to
faffbbc
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅ ✅ All tests successful. No failed tests found. Additional details and impacted files@@ Coverage Diff @@
## master #83160 +/- ##
==========================================
- Coverage 74.90% 66.61% -8.30%
==========================================
Files 9481 9481
Lines 537568 537565 -3
Branches 21174 21174
==========================================
- Hits 402681 358085 -44596
- Misses 134531 176033 +41502
- Partials 356 3447 +3091 |
When firing actions, utilize the new
ActionGroupStatus
table to check if that action should be firing, given how long ago it last fired for the group and thefrequency
configured inworkflow.config
(default 30 min).This involves some Django annotations and hopping through quite a few lookup tables to go from Action to Workflow 😓