Skip to content

Commit a5bd4b8

Browse files
feat(insights): Updates web vitals issue detection task to check if seer is enabled (#102674)
Updates `web_vitals_issue_detection` to check if project has seer feature flags, seer acknowledgement, and github codemapping
1 parent 88e5bd0 commit a5bd4b8

File tree

2 files changed

+136
-9
lines changed

2 files changed

+136
-9
lines changed

src/sentry/tasks/web_vitals_issue_detection.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import logging
44
from datetime import UTC, datetime, timedelta
55

6-
from sentry import options
6+
from sentry import features, options
77
from sentry.models.project import Project
88
from sentry.search.eap.types import SearchResolverConfig
99
from sentry.search.events.types import SnubaParams
10+
from sentry.seer.autofix.utils import get_autofix_repos_from_project_code_mappings
11+
from sentry.seer.constants import SEER_SUPPORTED_SCM_PROVIDERS
1012
from sentry.seer.explorer.utils import normalize_description
13+
from sentry.seer.seer_setup import get_seer_org_acknowledgement
1114
from sentry.snuba.referrer import Referrer
1215
from sentry.snuba.spans_rpc import Spans
1316
from sentry.tasks.base import instrumented_task
@@ -53,8 +56,13 @@ def run_web_vitals_issue_detection() -> None:
5356
return
5457

5558
# Spawn a sub-task for each project
56-
for project_id in enabled_project_ids:
57-
detect_web_vitals_issues_for_project.delay(project_id)
59+
projects = Project.objects.filter(id__in=enabled_project_ids).select_related("organization")
60+
61+
for project in projects:
62+
if not check_seer_setup_for_project(project):
63+
continue
64+
65+
detect_web_vitals_issues_for_project.delay(project.id)
5866

5967

6068
@instrumented_task(
@@ -183,3 +191,25 @@ def get_highest_opportunity_page_vitals_for_project(
183191
)
184192

185193
return web_vital_issue_groups
194+
195+
196+
def check_seer_setup_for_project(project: Project) -> bool:
197+
"""
198+
Checks if a project and it's organization have the necessary Seer setup to detect web vitals issues.
199+
The project must have seer feature flags, seer acknowledgement, and a github code mapping.
200+
"""
201+
if not features.has("organizations:gen-ai-features", project.organization):
202+
return False
203+
204+
if project.organization.get_option("sentry:hide_ai_features"):
205+
return False
206+
207+
if not get_seer_org_acknowledgement(project.organization):
208+
return False
209+
210+
repos = get_autofix_repos_from_project_code_mappings(project)
211+
github_repos = [repo for repo in repos if repo.get("provider") in SEER_SUPPORTED_SCM_PROVIDERS]
212+
if not github_repos:
213+
return False
214+
215+
return True

tests/sentry/tasks/test_web_vitals_issue_detection.py

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from contextlib import contextmanager
12
from unittest.mock import patch
23

34
import pytest
@@ -16,21 +17,105 @@ def setUp(self):
1617
super().setUp()
1718
self.ten_mins_ago = before_now(minutes=10)
1819

20+
@contextmanager
21+
def mock_seer_ack(self):
22+
with (
23+
patch(
24+
"sentry.tasks.web_vitals_issue_detection.get_seer_org_acknowledgement"
25+
) as mock_ack,
26+
):
27+
mock_ack.return_value = True
28+
yield {"mock_ack": mock_ack}
29+
30+
@contextmanager
31+
def mock_code_mapping(self):
32+
with (
33+
patch(
34+
"sentry.tasks.web_vitals_issue_detection.get_autofix_repos_from_project_code_mappings"
35+
) as mock_repos,
36+
):
37+
mock_repos.return_value = [
38+
{
39+
"provider": "integrations:github",
40+
"owner": "test-owner",
41+
"name": "test-repo",
42+
}
43+
]
44+
yield {"mock_repos": mock_repos}
45+
1946
@patch("sentry.tasks.web_vitals_issue_detection.detect_web_vitals_issues_for_project.delay")
20-
def test_run_detection_dispatches_sub_tasks(self, mock_delay):
47+
def test_run_detection_dispatches_sub_tasks_when_enabled(self, mock_delay):
2148
project = self.create_project()
2249

23-
with self.options(
24-
{
25-
"issue-detection.web-vitals-detection.enabled": True,
26-
"issue-detection.web-vitals-detection.projects-allowlist": [project.id],
27-
}
50+
with (
51+
self.mock_seer_ack(),
52+
self.mock_code_mapping(),
53+
self.options(
54+
{
55+
"issue-detection.web-vitals-detection.enabled": True,
56+
"issue-detection.web-vitals-detection.projects-allowlist": [project.id],
57+
}
58+
),
59+
self.feature("organizations:gen-ai-features"),
2860
):
2961
run_web_vitals_issue_detection()
3062

3163
assert mock_delay.called
3264
assert mock_delay.call_args[0][0] == project.id
3365

66+
@patch("sentry.tasks.web_vitals_issue_detection.detect_web_vitals_issues_for_project.delay")
67+
def test_run_detection_skips_when_seer_not_acknowledged(self, mock_delay):
68+
project = self.create_project()
69+
70+
with (
71+
self.mock_code_mapping(),
72+
self.options(
73+
{
74+
"issue-detection.web-vitals-detection.enabled": True,
75+
"issue-detection.web-vitals-detection.projects-allowlist": [project.id],
76+
}
77+
),
78+
self.feature("organizations:gen-ai-features"),
79+
):
80+
run_web_vitals_issue_detection()
81+
82+
assert not mock_delay.called
83+
84+
@patch("sentry.tasks.web_vitals_issue_detection.detect_web_vitals_issues_for_project.delay")
85+
def test_run_detection_skips_when_no_github_code_mappings(self, mock_delay):
86+
project = self.create_project()
87+
88+
with (
89+
self.mock_seer_ack(),
90+
self.options(
91+
{
92+
"issue-detection.web-vitals-detection.enabled": True,
93+
"issue-detection.web-vitals-detection.projects-allowlist": [project.id],
94+
}
95+
),
96+
self.feature("organizations:gen-ai-features"),
97+
):
98+
run_web_vitals_issue_detection()
99+
100+
assert not mock_delay.called
101+
102+
@patch("sentry.tasks.web_vitals_issue_detection.detect_web_vitals_issues_for_project.delay")
103+
def test_run_detection_skips_when_not_allowlisted(self, mock_delay):
104+
with (
105+
self.mock_seer_ack(),
106+
self.mock_code_mapping(),
107+
self.options(
108+
{
109+
"issue-detection.web-vitals-detection.enabled": True,
110+
"issue-detection.web-vitals-detection.projects-allowlist": [],
111+
}
112+
),
113+
self.feature("organizations:gen-ai-features"),
114+
):
115+
run_web_vitals_issue_detection()
116+
117+
assert not mock_delay.called
118+
34119
@pytest.mark.snuba
35120
@patch("sentry.web_vitals.issue_platform_adapter.produce_occurrence_to_kafka")
36121
def test_run_detection_produces_occurrences(self, mock_produce_occurrence_to_kafka):
@@ -110,12 +195,15 @@ def test_run_detection_produces_occurrences(self, mock_produce_occurrence_to_kaf
110195
self.store_spans(spans, is_eap=True)
111196

112197
with (
198+
self.mock_seer_ack(),
199+
self.mock_code_mapping(),
113200
self.options(
114201
{
115202
"issue-detection.web-vitals-detection.enabled": True,
116203
"issue-detection.web-vitals-detection.projects-allowlist": [project.id],
117204
}
118205
),
206+
self.feature("organizations:gen-ai-features"),
119207
TaskRunner(),
120208
):
121209
run_web_vitals_issue_detection()
@@ -209,12 +297,15 @@ def test_run_detection_does_not_produce_occurrences_for_existing_issues(
209297
)
210298

211299
with (
300+
self.mock_seer_ack(),
301+
self.mock_code_mapping(),
212302
self.options(
213303
{
214304
"issue-detection.web-vitals-detection.enabled": True,
215305
"issue-detection.web-vitals-detection.projects-allowlist": [project.id],
216306
}
217307
),
308+
self.feature("organizations:gen-ai-features"),
218309
TaskRunner(),
219310
):
220311
run_web_vitals_issue_detection()
@@ -251,12 +342,15 @@ def test_run_detection_does_not_create_issue_on_insufficient_samples(
251342
self.store_spans(spans, is_eap=True)
252343

253344
with (
345+
self.mock_seer_ack(),
346+
self.mock_code_mapping(),
254347
self.options(
255348
{
256349
"issue-detection.web-vitals-detection.enabled": True,
257350
"issue-detection.web-vitals-detection.projects-allowlist": [project.id],
258351
}
259352
),
353+
self.feature("organizations:gen-ai-features"),
260354
TaskRunner(),
261355
):
262356
run_web_vitals_issue_detection()
@@ -330,12 +424,15 @@ def test_run_detection_selects_trace_closest_to_p75_web_vital_value(
330424
self.store_spans(spans, is_eap=True)
331425

332426
with (
427+
self.mock_seer_ack(),
428+
self.mock_code_mapping(),
333429
self.options(
334430
{
335431
"issue-detection.web-vitals-detection.enabled": True,
336432
"issue-detection.web-vitals-detection.projects-allowlist": [project.id],
337433
}
338434
),
435+
self.feature("organizations:gen-ai-features"),
339436
TaskRunner(),
340437
):
341438
run_web_vitals_issue_detection()

0 commit comments

Comments
 (0)