Skip to content
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

Closed
wants to merge 12 commits into from

Conversation

cathteng
Copy link
Member

@cathteng cathteng commented Apr 1, 2025

Refactor the process of firing actions to:

  1. Create WorkflowFireHistory objects for each unique workflow being fired
  2. Grab the correct notification_uuid from the WorkflowFireHistory objects to fire each Action with
  3. Update the WorkflowEventData correctly with workflow_env and workflow_id to fire each Action with

Refactors into a single function that can be used in process_workflows AND delayed workflow processing 😇

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Apr 1, 2025
Copy link

codecov bot commented Apr 1, 2025

Codecov Report

All 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              

@cathteng cathteng force-pushed the cathy/aci/use-workflow-fire-history branch from 22e6926 to 0a3780b Compare April 2, 2025 16:04
Base automatically changed from cathy/aci/workflow-fire-history-model to master April 2, 2025 17:50
@cathteng cathteng force-pushed the cathy/aci/use-workflow-fire-history branch from 0a3780b to 6f3b932 Compare April 3, 2025 01:18
return workflow_id_to_fire_history


def fire_actions(actions: list[Action], detector: Detector, event_data: WorkflowEventData) -> None:
Copy link
Member Author

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?

Copy link
Contributor

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.

@cathteng cathteng marked this pull request as ready for review April 3, 2025 01:24
@cathteng cathteng requested a review from a team as a code owner April 3, 2025 01:24
@cathteng cathteng requested a review from iamrajjoshi April 3, 2025 01:27
Copy link
Contributor

@saponifi3d saponifi3d left a 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:
Copy link
Contributor

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:
Copy link
Contributor

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.

Comment on lines +39 to +83
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
Copy link
Contributor

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(
Copy link
Contributor

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()))
Copy link
Contributor

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

Comment on lines +55 to +56
# TODO: account for actions being attached to multiple workflows?
# should you even send multiple notifications then? :think:
Copy link
Contributor

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]:
Copy link
Contributor

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")
Copy link
Member

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
Copy link
Member

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?

Copy link
Member Author

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

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
)

Copy link
Member

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?

Comment on lines +55 to +56
# TODO: account for actions being attached to multiple workflows?
# should you even send multiple notifications then? :think:
Copy link
Member

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?

Copy link
Contributor

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.

@cathteng cathteng requested a review from GabeVillalobos April 3, 2025 18:37
@cathteng cathteng marked this pull request as draft April 3, 2025 20:17
@cathteng
Copy link
Member Author

cathteng commented Apr 7, 2025

Replacing with #88775

@cathteng cathteng closed this Apr 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants