Skip to content

Commit 195d699

Browse files
authored
ref(grouping): Always use default config when loading unknown config (#96610)
Currently, we have inconsistent behavior when loading a grouping config with an id we don't recognize. If the config id comes from the project, and we've therefore gotten it by using `ProjectGroupingConfigLoader._get_config_id`, it's guaranteed to be one we've heard of, because if it's not, `_get_config_id` will instead return the id of the default config[1]. If instead the config id comes from an event's `grouping_config` entry (which we grab with no validation[2]), trying to load the grouping config will raise a `GroupingConfigNotFound` error[3]. To make the behavior consistent, this switches from raising the error in the latter case to just returning the default config. Since this was the only place we were raising `GroupingConfigNotFound`, this also lets us remove all of our handling of it, as well as the error class itself. [1] https://github.com/getsentry/sentry/blob/65fa0a9af7d186bc5142cf85e6fdb9a59e08a406/src/sentry/grouping/api.py#L147-L148 [2] https://github.com/getsentry/sentry/blob/65fa0a9af7d186bc5142cf85e6fdb9a59e08a406/src/sentry/grouping/api.py#L190 [3] https://github.com/getsentry/sentry/blob/65fa0a9af7d186bc5142cf85e6fdb9a59e08a406/src/sentry/grouping/api.py#L229-L230
1 parent bf052e4 commit 195d699

File tree

5 files changed

+35
-37
lines changed

5 files changed

+35
-37
lines changed

src/sentry/grouping/api.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,6 @@ class GroupHashInfo:
6868
NULL_GROUPHASH_INFO = GroupHashInfo(NULL_GROUPING_CONFIG, {}, [], [], None)
6969

7070

71-
class GroupingConfigNotFound(LookupError):
72-
pass
73-
74-
7571
class GroupingConfig(TypedDict):
7672
id: str
7773
enhancements: str
@@ -220,14 +216,18 @@ def get_default_grouping_config_dict(config_id: str | None = None) -> GroupingCo
220216

221217

222218
def load_grouping_config(config_dict: GroupingConfig | None = None) -> StrategyConfiguration:
223-
"""Loads the given grouping config."""
219+
"""
220+
Load the given grouping config, or the default config if none is provided or if the given
221+
config is not recognized.
222+
"""
224223
if config_dict is None:
225224
config_dict = get_default_grouping_config_dict()
226225
elif "id" not in config_dict:
227226
raise ValueError("Malformed configuration dictionary")
228227
config_id = config_dict["id"]
229228
if config_id not in CONFIGURATIONS:
230-
raise GroupingConfigNotFound(config_id)
229+
config_dict = get_default_grouping_config_dict()
230+
config_id = config_dict["id"]
231231
return CONFIGURATIONS[config_id](enhancements=config_dict["enhancements"])
232232

233233

src/sentry/grouping/grouping_info.py

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import logging
22
from typing import Any
33

4-
from sentry.api.exceptions import ResourceDoesNotExist
54
from sentry.eventstore.models import Event, GroupEvent
6-
from sentry.grouping.api import GroupingConfigNotFound
75
from sentry.grouping.variants import BaseVariant, PerformanceProblemVariant
86
from sentry.models.project import Project
97
from sentry.performance_issues.performance_detection import EventPerformanceProblem
@@ -20,29 +18,23 @@ def get_grouping_info(
2018
# produced hashes that would normally also appear in the event.
2119
hashes = event.get_hashes()
2220

23-
try:
24-
if event.get_event_type() == "transaction":
25-
# Transactions events are grouped using performance detection. They
26-
# are not subject to grouping configs, and the only relevant
27-
# grouping variant is `PerformanceProblemVariant`.
28-
29-
problems = EventPerformanceProblem.fetch_multi([(event, h) for h in hashes])
30-
31-
# Create a variant for every problem associated with the event
32-
# TODO: Generate more unique keys, in case this event has more than
33-
# one problem of a given type
34-
variants: dict[str, BaseVariant] = {
35-
problem.problem.type.slug: PerformanceProblemVariant(problem)
36-
for problem in problems
37-
if problem
38-
}
39-
else:
40-
variants = event.get_grouping_variants(
41-
force_config=config_name, normalize_stacktraces=True
42-
)
43-
44-
except GroupingConfigNotFound:
45-
raise ResourceDoesNotExist(detail="Unknown grouping config")
21+
if event.get_event_type() == "transaction":
22+
# Transactions events are grouped using performance detection. They
23+
# are not subject to grouping configs, and the only relevant
24+
# grouping variant is `PerformanceProblemVariant`.
25+
26+
problems = EventPerformanceProblem.fetch_multi([(event, h) for h in hashes])
27+
28+
# Create a variant for every problem associated with the event
29+
# TODO: Generate more unique keys, in case this event has more than
30+
# one problem of a given type
31+
variants: dict[str, BaseVariant] = {
32+
problem.problem.type.slug: PerformanceProblemVariant(problem)
33+
for problem in problems
34+
if problem
35+
}
36+
else:
37+
variants = event.get_grouping_variants(force_config=config_name, normalize_stacktraces=True)
4638

4739
grouping_info = get_grouping_info_from_variants(variants)
4840

src/sentry/tasks/embeddings_grouping/backfill_seer_grouping_records_for_project.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from sentry import options
77
from sentry.api.exceptions import ResourceDoesNotExist
8-
from sentry.grouping.api import GroupingConfigNotFound
98
from sentry.grouping.enhancer.exceptions import InvalidEnhancerConfig
109
from sentry.models.project import Project
1110
from sentry.seer.similarity.utils import (
@@ -35,7 +34,7 @@
3534
from sentry.utils import metrics
3635

3736
SEER_ACCEPTABLE_FAILURE_REASONS = ["Gateway Timeout", "Service Unavailable"]
38-
EVENT_INFO_EXCEPTIONS = (GroupingConfigNotFound, ResourceDoesNotExist, InvalidEnhancerConfig)
37+
EVENT_INFO_EXCEPTIONS = (ResourceDoesNotExist, InvalidEnhancerConfig)
3938

4039
logger = logging.getLogger(__name__)
4140

tests/sentry/api/endpoints/test_event_grouping_info.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import pytest
55
from django.urls import reverse
66

7-
from sentry.api.exceptions import ResourceDoesNotExist
7+
from sentry.conf.server import DEFAULT_GROUPING_CONFIG
88
from sentry.grouping.grouping_info import get_grouping_info
99
from sentry.testutils.cases import APITestCase, PerformanceIssueTestCase
1010
from sentry.testutils.skips import requires_snuba
@@ -113,12 +113,20 @@ def test_no_event(self) -> None:
113113
assert response.status_text == "Not Found"
114114

115115
def test_get_grouping_info_unkown_grouping_config(self) -> None:
116+
"""Show we use the default config when the config we're given is unrecognized"""
117+
116118
data = load_data(platform="javascript")
117119
event = self.store_event(data=data, project_id=self.project.id)
118120

119-
with pytest.raises(ResourceDoesNotExist):
121+
with mock.patch(
122+
"sentry.grouping.api.get_grouping_variants_for_event"
123+
) as mock_get_grouping_variants:
120124
get_grouping_info("fake-config", self.project, event)
121125

126+
mock_get_grouping_variants.assert_called_once()
127+
assert mock_get_grouping_variants.call_args.args[0] == event
128+
assert mock_get_grouping_variants.call_args.args[1].id == DEFAULT_GROUPING_CONFIG
129+
122130
@mock.patch("sentry.grouping.grouping_info.logger")
123131
@mock.patch("sentry.grouping.grouping_info.metrics")
124132
def test_get_grouping_info_hash_mismatch(self, mock_metrics, mock_logger):

tests/sentry/tasks/test_backfill_seer_grouping_records.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from sentry.conf.server import SEER_SIMILARITY_MODEL_VERSION
2020
from sentry.db.models.manager.base_query_set import BaseQuerySet
2121
from sentry.eventstore.models import Event
22-
from sentry.grouping.api import GroupingConfigNotFound
2322
from sentry.grouping.enhancer.exceptions import InvalidEnhancerConfig
2423
from sentry.models.group import Group, GroupStatus
2524
from sentry.models.grouphash import GroupHash
@@ -1150,7 +1149,7 @@ def test_empty_nodestore(
11501149
def test_nodestore_grouping_config_not_found(
11511150
self, mock_call_next_backfill, mock_lookup_group_data_stacktrace_bulk
11521151
):
1153-
exceptions = (GroupingConfigNotFound(), ResourceDoesNotExist(), InvalidEnhancerConfig())
1152+
exceptions = (ResourceDoesNotExist(), InvalidEnhancerConfig())
11541153

11551154
for exception in exceptions:
11561155
mock_lookup_group_data_stacktrace_bulk.side_effect = exception

0 commit comments

Comments
 (0)