Skip to content

Commit 45b155c

Browse files
getsentry-botcathteng
authored andcommitted
Revert "ref(aci): remove passing in detector to action.trigger (#103000)"
This reverts commit bfaacc5. Co-authored-by: cathteng <70817427+cathteng@users.noreply.github.com>
1 parent 30838ab commit 45b155c

File tree

10 files changed

+77
-76
lines changed

10 files changed

+77
-76
lines changed

src/sentry/api/endpoints/project_rule_actions.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from sentry.workflow_engine.migration_helpers.rule_action import (
2626
translate_rule_data_actions_to_notification_actions,
2727
)
28-
from sentry.workflow_engine.models import Workflow
28+
from sentry.workflow_engine.models import Detector, Workflow
2929
from sentry.workflow_engine.types import WorkflowEventData
3030

3131
logger = logging.getLogger(__name__)
@@ -161,6 +161,14 @@ def execute_future_on_test_event_workflow_engine(
161161
organization=rule.project.organization,
162162
)
163163

164+
detector = Detector(
165+
id=TEST_NOTIFICATION_ID,
166+
project=rule.project,
167+
name=rule.label,
168+
enabled=True,
169+
type=ErrorGroupType.slug,
170+
)
171+
164172
event_data = WorkflowEventData(
165173
event=test_event,
166174
group=test_event.group,
@@ -182,7 +190,7 @@ def execute_future_on_test_event_workflow_engine(
182190
action_exceptions.append(f"An unexpected error occurred. Error ID: '{error_id}'")
183191
continue
184192

185-
action_exceptions.extend(test_fire_action(action, event_data))
193+
action_exceptions.extend(test_fire_action(action, event_data, detector))
186194

187195
status = None
188196
data = None

src/sentry/workflow_engine/endpoints/organization_test_fire_action.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
)
2424
from sentry.workflow_engine.endpoints.utils.test_fire_action import test_fire_action
2525
from sentry.workflow_engine.endpoints.validators.base.action import BaseActionValidator
26-
from sentry.workflow_engine.models import Action
26+
from sentry.workflow_engine.models import Action, Detector
2727
from sentry.workflow_engine.types import WorkflowEventData
2828

2929
logger = logging.getLogger(__name__)
@@ -121,6 +121,14 @@ def test_fire_actions(actions: list[dict[str, Any]], project: Project):
121121
group=test_event.group,
122122
)
123123

124+
detector = Detector(
125+
id=TEST_NOTIFICATION_ID,
126+
project=project,
127+
name="Test Detector",
128+
enabled=True,
129+
type="error",
130+
)
131+
124132
for action_data in actions:
125133
# Create a temporary Action object (not saved to database)
126134
action = Action(
@@ -135,7 +143,7 @@ def test_fire_actions(actions: list[dict[str, Any]], project: Project):
135143
setattr(action, "workflow_id", workflow_id)
136144

137145
# Test fire the action and collect any exceptions
138-
exceptions = test_fire_action(action, workflow_event_data)
146+
exceptions = test_fire_action(action, workflow_event_data, detector)
139147
if exceptions:
140148
action_exceptions.extend(exceptions)
141149

src/sentry/workflow_engine/endpoints/utils/test_fire_action.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@
33
import sentry_sdk
44

55
from sentry.shared_integrations.exceptions import IntegrationFormError
6-
from sentry.workflow_engine.models import Action
6+
from sentry.workflow_engine.models import Action, Detector
77
from sentry.workflow_engine.types import WorkflowEventData
88

99
logger = logging.getLogger(__name__)
1010

1111

12-
def test_fire_action(action: Action, event_data: WorkflowEventData) -> list[str]:
12+
def test_fire_action(
13+
action: Action, event_data: WorkflowEventData, detector: Detector
14+
) -> list[str]:
1315
"""
1416
This function will fire an action and return a list of exceptions that occurred.
1517
"""
1618
action_exceptions = []
1719
try:
1820
action.trigger(
1921
event_data=event_data,
22+
detector=detector,
2023
)
2124
except Exception as exc:
2225
if isinstance(exc, IntegrationFormError):

src/sentry/workflow_engine/models/action.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import builtins
44
import logging
55
from enum import StrEnum
6-
from typing import ClassVar
6+
from typing import TYPE_CHECKING, ClassVar
77

88
from django.db import models
99
from django.db.models import Q
@@ -23,6 +23,10 @@
2323
from sentry.workflow_engine.registry import action_handler_registry
2424
from sentry.workflow_engine.types import ActionHandler, WorkflowEventData
2525

26+
if TYPE_CHECKING:
27+
from sentry.workflow_engine.models import Detector
28+
29+
2630
logger = logging.getLogger(__name__)
2731

2832

@@ -112,10 +116,7 @@ def get_handler(self) -> builtins.type[ActionHandler]:
112116
action_type = Action.Type(self.type)
113117
return action_handler_registry.get(action_type)
114118

115-
def trigger(self, event_data: WorkflowEventData) -> None:
116-
from sentry.workflow_engine.processors.detector import get_detector_by_event
117-
118-
detector = get_detector_by_event(event_data)
119+
def trigger(self, event_data: WorkflowEventData, detector: Detector) -> None:
119120
with metrics.timer(
120121
"workflow_engine.action.trigger.execution_time",
121122
tags={"action_type": self.type, "detector_type": detector.type},

src/sentry/workflow_engine/tasks/actions.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def build_trigger_action_task_params(
6767
@retry(timeouts=True, raise_on_no_retries=False, ignore_and_capture=Action.DoesNotExist)
6868
def trigger_action(
6969
action_id: int,
70+
detector_id: int,
7071
workflow_id: int,
7172
event_id: str | None,
7273
activity_id: int | None,
@@ -75,10 +76,8 @@ def trigger_action(
7576
group_state: GroupState,
7677
has_reappeared: bool,
7778
has_escalated: bool,
78-
detector_id: int | None = None,
7979
) -> None:
8080
from sentry.notifications.notification_action.utils import should_fire_workflow_actions
81-
from sentry.workflow_engine.processors.detector import get_detector_by_event
8281

8382
# XOR check to ensure exactly one of event_id or activity_id is provided
8483
if (event_id is not None) == (activity_id is not None):
@@ -89,14 +88,19 @@ def trigger_action(
8988
raise ValueError("Exactly one of event_id or activity_id must be provided")
9089

9190
action = Action.objects.annotate(workflow_id=Value(workflow_id)).get(id=action_id)
91+
detector = Detector.objects.get(id=detector_id)
9292

93-
# TODO: remove detector usage from this task
94-
detector: Detector | None = None
95-
if detector_id is not None:
96-
detector = Detector.objects.get(id=detector_id)
93+
metrics.incr(
94+
"workflow_engine.tasks.trigger_action_task_started",
95+
tags={"action_type": action.type, "detector_type": detector.type},
96+
sample_rate=1.0,
97+
)
98+
99+
project_id = detector.project_id
97100

98101
if event_id is not None:
99102
event_data = build_workflow_event_data_from_event(
103+
project_id=project_id,
100104
event_id=event_id,
101105
group_id=group_id,
102106
workflow_id=workflow_id,
@@ -118,15 +122,6 @@ def trigger_action(
118122
)
119123
raise ValueError("Exactly one of event_id or activity_id must be provided")
120124

121-
if detector is None:
122-
detector = get_detector_by_event(event_data)
123-
124-
metrics.incr(
125-
"workflow_engine.tasks.trigger_action_task_started",
126-
tags={"action_type": action.type, "detector_type": detector.type},
127-
sample_rate=1.0,
128-
)
129-
130125
should_trigger_actions = should_fire_workflow_actions(
131126
detector.project.organization, event_data.group.type
132127
)
@@ -135,7 +130,7 @@ def trigger_action(
135130
# Set up a timeout grouping context because we want to make sure any Sentry timeout reporting
136131
# in this scope is grouped properly.
137132
with timeout_grouping_context(action.type):
138-
action.trigger(event_data)
133+
action.trigger(event_data, detector)
139134
else:
140135
logger.info(
141136
"workflow_engine.triggered_actions.dry-run",

src/sentry/workflow_engine/tasks/utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def __init__(self, event_id: str, project_id: int):
6464

6565
@scopedstats.timer()
6666
def build_workflow_event_data_from_event(
67+
project_id: int,
6768
event_id: str,
6869
group_id: int,
6970
workflow_id: int | None = None,
@@ -77,14 +78,14 @@ def build_workflow_event_data_from_event(
7778
This method handles all the database fetching and object construction logic.
7879
Raises EventNotFoundError if the event is not found.
7980
"""
80-
group = Group.objects.get_from_cache(id=group_id)
81-
project_id = group.project_id
81+
8282
event = fetch_event(event_id, project_id)
8383
if event is None:
8484
raise EventNotFoundError(event_id, project_id)
8585

8686
occurrence = IssueOccurrence.fetch(occurrence_id, project_id) if occurrence_id else None
8787

88+
group = Group.objects.get_from_cache(id=group_id)
8889
group_event = GroupEvent.from_event(event, group)
8990
group_event.occurrence = occurrence
9091

src/sentry/workflow_engine/tasks/workflows.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ def process_workflow_activity(activity_id: int, group_id: int, detector_id: int)
9393
on_silent=DataConditionGroup.DoesNotExist,
9494
)
9595
def process_workflows_event(
96+
project_id: int,
9697
event_id: str,
9798
group_id: int,
9899
occurrence_id: str | None,
99100
group_state: GroupState,
100101
has_reappeared: bool,
101102
has_escalated: bool,
102103
start_timestamp_seconds: float | None = None,
103-
project_id: int | None = None,
104104
**kwargs: dict[str, Any],
105105
) -> None:
106106
from sentry.workflow_engine.buffer.batch_client import DelayedWorkflowClient
@@ -111,6 +111,7 @@ def process_workflows_event(
111111
with recorder.record():
112112
try:
113113
event_data = build_workflow_event_data_from_event(
114+
project_id=project_id,
114115
event_id=event_id,
115116
group_id=group_id,
116117
occurrence_id=occurrence_id,

tests/sentry/workflow_engine/endpoints/test_organization_test_fire_action.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from sentry.testutils.silo import assume_test_silo_mode
2222
from sentry.testutils.skips import requires_snuba
2323
from sentry.workflow_engine.models import Action
24-
from sentry.workflow_engine.typings.grouptype import IssueStreamGroupType
2524
from tests.sentry.workflow_engine.test_base import BaseWorkflowTest
2625

2726
pytestmark = [requires_snuba]
@@ -35,10 +34,6 @@ def setUp(self) -> None:
3534
super().setUp()
3635
self.login_as(self.user)
3736
self.project = self.create_project(organization=self.organization)
38-
self.detector = self.create_detector(project=self.project)
39-
self.issue_stream_detector = self.create_detector(
40-
project=self.project, type=IssueStreamGroupType.slug
41-
)
4237
self.workflow = self.create_workflow()
4338

4439
def setup_pd_service(self) -> PagerDutyServiceDict:
@@ -95,7 +90,7 @@ def test_pagerduty_action(
9590
assert response.status_code == 200
9691
assert mock_send_trigger.call_count == 1
9792
pagerduty_data = mock_send_trigger.call_args.kwargs.get("data")
98-
assert pagerduty_data["payload"]["summary"].startswith(f"[{self.detector.name}]:")
93+
assert pagerduty_data["payload"]["summary"].startswith("[Test Detector]:")
9994

10095
@mock.patch.object(NotifyEventAction, "after")
10196
@mock.patch(

tests/sentry/workflow_engine/handlers/action/test_action_handlers.py

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,13 @@
22

33
from sentry.grouping.grouptype import ErrorGroupType
44
from sentry.incidents.grouptype import MetricIssue
5-
from sentry.types.group import PriorityLevel
65
from sentry.utils.registry import NoRegistrationExistsError
76
from sentry.workflow_engine.models import Action
87
from sentry.workflow_engine.types import WorkflowEventData
9-
from tests.sentry.notifications.notification_action.test_metric_alert_registry_handlers import (
10-
MetricAlertHandlerBase,
11-
)
8+
from tests.sentry.workflow_engine.test_base import BaseWorkflowTest
129

1310

14-
class TestNotificationActionHandler(MetricAlertHandlerBase):
11+
class TestNotificationActionHandler(BaseWorkflowTest):
1512
def setUp(self) -> None:
1613
super().setUp()
1714
self.project = self.create_project()
@@ -20,6 +17,18 @@ def setUp(self) -> None:
2017
self.group, self.event, self.group_event = self.create_group_event()
2118
self.event_data = WorkflowEventData(event=self.group_event, group=self.group)
2219

20+
@mock.patch("sentry.notifications.notification_action.utils.execute_via_issue_alert_handler")
21+
def test_execute_without_group_type(
22+
self, mock_execute_via_issue_alert_handler: mock.MagicMock
23+
) -> None:
24+
"""Test that execute does nothing when detector has no group_type"""
25+
self.detector.type = ""
26+
self.action.trigger(self.event_data, self.detector)
27+
28+
mock_execute_via_issue_alert_handler.assert_called_once_with(
29+
self.event_data, self.action, self.detector
30+
)
31+
2332
@mock.patch(
2433
"sentry.notifications.notification_action.registry.group_type_notification_registry.get"
2534
)
@@ -31,7 +40,7 @@ def test_execute_error_group_type(self, mock_registry_get: mock.MagicMock) -> No
3140
mock_handler = mock.Mock()
3241
mock_registry_get.return_value = mock_handler
3342

34-
self.action.trigger(self.event_data)
43+
self.action.trigger(self.event_data, self.detector)
3544

3645
mock_registry_get.assert_called_once_with(ErrorGroupType.slug)
3746
mock_handler.handle_workflow_action.assert_called_once_with(
@@ -47,25 +56,10 @@ def test_execute_metric_alert_type(self, mock_registry_get: mock.MagicMock) -> N
4756
self.detector.config = {"threshold_period": 1, "detection_type": "static"}
4857
self.detector.save()
4958

50-
self.group.type = MetricIssue.type_id
51-
self.group.save()
52-
53-
group, _, group_event = self.create_group_event(
54-
group_type_id=MetricIssue.type_id,
55-
occurrence=self.create_issue_occurrence(
56-
priority=PriorityLevel.HIGH.value,
57-
level="error",
58-
evidence_data={
59-
"detector_id": self.detector.id,
60-
},
61-
),
62-
)
63-
self.event_data = WorkflowEventData(event=group_event, group=group)
64-
6559
mock_handler = mock.Mock()
6660
mock_registry_get.return_value = mock_handler
6761

68-
self.action.trigger(self.event_data)
62+
self.action.trigger(self.event_data, self.detector)
6963

7064
mock_registry_get.assert_called_once_with(MetricIssue.slug)
7165
mock_handler.handle_workflow_action.assert_called_once_with(
@@ -78,15 +72,15 @@ def test_execute_metric_alert_type(self, mock_registry_get: mock.MagicMock) -> N
7872
side_effect=NoRegistrationExistsError,
7973
)
8074
@mock.patch("sentry.notifications.notification_action.utils.logger")
81-
def test_execute_unknown_detector(
75+
def test_execute_unknown_group_type(
8276
self,
8377
mock_logger: mock.MagicMock,
8478
mock_registry_get: mock.MagicMock,
8579
mock_execute_via_issue_alert_handler: mock.MagicMock,
8680
) -> None:
87-
"""Test that execute does nothing when we can't find the detector"""
81+
"""Test that execute does nothing when detector has no group_type"""
8882

89-
self.action.trigger(self.event_data)
83+
self.action.trigger(self.event_data, self.detector)
9084

9185
mock_logger.warning.assert_called_once_with(
9286
"group_type_notification_registry.get.NoRegistrationExistsError",

0 commit comments

Comments
 (0)