-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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): create WorkflowFireHistory objects when workflows fire for a group #88495
Conversation
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 #88495 +/- ##
==========================================
+ Coverage 84.49% 87.76% +3.26%
==========================================
Files 10032 10032
Lines 567910 567979 +69
Branches 22270 22270
==========================================
+ Hits 479856 498472 +18616
+ Misses 87634 69087 -18547
Partials 420 420 |
22e6926
to
0a3780b
Compare
0a3780b
to
6f3b932
Compare
return workflow_id_to_fire_history | ||
|
||
|
||
def fire_actions(actions: list[Action], detector: Detector, event_data: WorkflowEventData) -> None: |
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.
not sure the correct home for this 🤔 could live in sentry/workflow_engine/processors/action.py
too?
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.
yeah, i think this belongs in that file rather than here. the focus is on triggering the 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 feel like there is a bit of cleanup to happen here, we should try not to add everything to the workflow file and split it up based on what we're processing.
i'm also curious how much of this code we might need.. we have a trigger_actions
method and now a fire_actions
method, we also already have a set list of actions to trigger and a list of the triggered workflows, but we're re-querying for that data here.
@@ -66,7 +66,7 @@ def get_handler(self) -> ActionHandler: | |||
action_type = Action.Type(self.type) | |||
return action_handler_registry.get(action_type) | |||
|
|||
def trigger(self, event_data: WorkflowEventData, detector: Detector) -> None: | |||
def trigger(self, event_data: WorkflowEventData, detector: Detector, uuid: str) -> None: |
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.
doesn't seem like we are using the uuid, can we remove it?
return workflow_id_to_fire_history | ||
|
||
|
||
def fire_actions(actions: list[Action], detector: Detector, event_data: WorkflowEventData) -> None: |
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.
yeah, i think this belongs in that file rather than here. the focus is on triggering the actions.
def get_actions_to_workflows(actions_to_fire: list[Action]) -> dict[int, Workflow]: | ||
action_ids = {action.id for action in actions_to_fire} | ||
workflow_actions = ( | ||
WorkflowDataConditionGroup.objects.select_related("workflow", "condition_group") | ||
.filter(condition_group__dataconditiongroupaction__action_id__in=action_ids) | ||
.values_list("condition_group__dataconditiongroupaction__action_id", "workflow_id") | ||
) | ||
|
||
action_to_workflows: dict[int, int] = { | ||
action_id: workflow_id for action_id, workflow_id in workflow_actions | ||
} | ||
workflow_ids = set(action_to_workflows.values()) | ||
|
||
workflows = Workflow.objects.filter(id__in=workflow_ids) | ||
workflow_ids_to_workflows = {workflow.id: workflow for workflow in workflows} | ||
|
||
# TODO: account for actions being attached to multiple workflows? | ||
# should you even send multiple notifications then? :think: | ||
actions_to_workflows: dict[int, Workflow] = { | ||
action_id: workflow_ids_to_workflows[workflow_id] | ||
for action_id, workflow_id in action_to_workflows.items() | ||
} | ||
return actions_to_workflows | ||
|
||
|
||
def create_workflow_fire_histories( | ||
actions_to_workflows: dict[int, Workflow], event_data: WorkflowEventData | ||
) -> dict[int, WorkflowFireHistory]: | ||
workflows = set(actions_to_workflows.values()) | ||
|
||
workflow_fire_histories = [ | ||
WorkflowFireHistory( | ||
workflow=workflow, | ||
group=event_data.event.group, | ||
event_id=event_data.event.event_id, | ||
) | ||
for workflow in workflows | ||
] | ||
fire_histories = WorkflowFireHistory.objects.bulk_create(workflow_fire_histories) | ||
|
||
workflow_id_to_fire_history: dict[int, WorkflowFireHistory] = { | ||
workflow_fire_history.workflow_id: workflow_fire_history | ||
for workflow_fire_history in fire_histories | ||
} | ||
return workflow_id_to_fire_history |
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 feel like we should make a processors/workflow_fire_history.py
to encapsulate hold this logic, that way we can keep this file focused on the pure workflow processing.
@@ -129,7 +196,9 @@ def evaluate_workflows_action_filters( | |||
return filter_recently_fired_workflow_actions(filtered_action_groups, event_data.event.group) | |||
|
|||
|
|||
def log_fired_workflows(log_name: str, actions: list[Action], job: WorkflowEventData) -> None: | |||
def log_fired_workflows( |
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.
should we move this into process/workflow_fire_history
file i proposed? 🤔
@@ -20,7 +21,7 @@ def setUp(self): | |||
def test_execute_without_group_type(self): | |||
"""Test that execute does nothing when detector has no group_type""" | |||
self.detector.type = "" | |||
self.action.trigger(self.event_data, self.detector) | |||
self.action.trigger(self.event_data, self.detector, str(uuid4())) |
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.
this uuid wasn't being used, can we remove this stuff?
curious about the plan around this uuid as well, i wonder if this is something we should encapsulate inside of self.action.trigger rather than exposing it in the params
# TODO: account for actions being attached to multiple workflows? | ||
# should you even send multiple notifications then? :think: |
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.
no, we should de-dupe the actions and only trigger them once. there was some stuff around that in trigger_actions
that i turned the action list for all the workflows into a set.
@@ -34,6 +36,71 @@ class WorkflowDataConditionGroupType(StrEnum): | |||
WORKFLOW_TRIGGER = "workflow_trigger" | |||
|
|||
|
|||
def get_actions_to_workflows(actions_to_fire: list[Action]) -> dict[int, Workflow]: |
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.
curious about this method at a high level, we already have a list of the actions that have been filtered to what will trigger. do we need to do this lookup?
def get_actions_to_workflows(actions_to_fire: list[Action]) -> dict[int, Workflow]: | ||
action_ids = {action.id for action in actions_to_fire} | ||
workflow_actions = ( | ||
WorkflowDataConditionGroup.objects.select_related("workflow", "condition_group") |
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 that select_related
is unnecessary, since you're already joining via values_list
.
event_data, workflow_env=workflow.environment, workflow_id=workflow.id | ||
) | ||
|
||
notification_uuid = workflow_id_to_fire_history[workflow.id].notification_uuid |
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.
Just checking - is the notification uuid meant to be shared between 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 didn't really understand why we did this because CTR should be tracked per action (unique uuid per action), but today we have it implemented as 1 UUID for all actions that fire for an issue alert
sentry/src/sentry/rules/processing/processor.py
Lines 414 to 418 in 342bab4
notification_uuid = str(uuid.uuid4()) | |
rule_fire_history = history.record(rule, self.group, self.event.event_id, notification_uuid) | |
grouped_futures = activate_downstream_actions( | |
rule, self.event, notification_uuid, rule_fire_history | |
) |
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.
Hmm... Do we use something else to differentiate the CTR by combining the uuid with the action name? Or are we just tracking incorrectly when multiple actions are set up?
# TODO: account for actions being attached to multiple workflows? | ||
# should you even send multiple notifications then? :think: |
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.
Can actions actually be attached to multiple workflows? I mean I know the data model supports it, but are there plans to support that?
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.
The thought is this is to support the eventual Notification Center
center project, which is pretty far down the line. we shouldn't be worrying tooo much about it today.
Replacing with #88775 |
Refactor the process of firing actions to:
WorkflowFireHistory
objects for each unique workflow being firednotification_uuid
from theWorkflowFireHistory
objects to fire eachAction
withWorkflowEventData
correctly withworkflow_env
andworkflow_id
to fire eachAction
withRefactors into a single function that can be used in
process_workflows
AND delayed workflow processing 😇