Skip to content

Commit 3884272

Browse files
authored
feat(occurrences on eap): Implement double reads from EAP for reprocessing2 flow (#109345)
Implements double reads of occurrences from EAP for `start_group_reprocessing` in `src/sentry/reprocessing2.py`.
1 parent bf7f90e commit 3884272

File tree

2 files changed

+129
-3
lines changed

2 files changed

+129
-3
lines changed

src/sentry/reprocessing2.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
import sentry_sdk
9696
from django.conf import settings
9797
from django.db import router
98+
from django.utils import timezone
9899

99100
from sentry import models, nodestore, options
100101
from sentry.attachments import CachedAttachment, attachment_cache, store_attachments_for_event
@@ -104,11 +105,15 @@
104105
from sentry.models.project import Project
105106
from sentry.objectstore import get_attachments_session
106107
from sentry.options.rollout import in_random_rollout
108+
from sentry.search.eap.occurrences.common_queries import count_occurrences
109+
from sentry.search.eap.occurrences.rollout_utils import EAPOccurrencesComparator
107110
from sentry.services import eventstore
108111
from sentry.services.eventstore.models import Event, GroupEvent
109112
from sentry.services.eventstore.processing import event_processing_store
110113
from sentry.services.eventstore.reprocessing import reprocessing_store
111114
from sentry.snuba.dataset import Dataset
115+
from sentry.snuba.occurrences_rpc import OccurrenceCategory
116+
from sentry.snuba.referrer import Referrer
112117
from sentry.types.activity import ActivityType
113118
from sentry.utils import metrics, snuba
114119
from sentry.utils.cache import cache_key_for_event
@@ -573,6 +578,9 @@ def start_group_reprocessing(
573578

574579
with transaction.atomic(router.db_for_write(models.Group)):
575580
group = models.Group.objects.get(id=group_id)
581+
project = group.project
582+
organization = project.organization
583+
group_first_seen = group.first_seen
576584
original_status = group.status
577585
original_substatus = group.substatus
578586
if original_status == models.GroupStatus.REPROCESSING:
@@ -628,14 +636,45 @@ def start_group_reprocessing(
628636
for model in GROUP_MODELS_TO_MIGRATE:
629637
model.objects.filter(group_id=group_id).update(group_id=new_group.id)
630638

631-
# Get event counts of issue (for all environments etc). This was copypasted
639+
# Get event counts of issue (for all environments etc). This was copy-pasted
632640
# and simplified from groupserializer.
633-
event_count = sync_count = snuba.aliased_query(
641+
referrer = Referrer.REPROCESSING2_START_GROUP_REPROCESSING.value
642+
snuba_count = snuba.aliased_query(
634643
aggregations=[["count()", "", "times_seen"]], # select
635644
dataset=Dataset.Events, # from
636645
conditions=[["group_id", "=", group_id], ["project_id", "=", project_id]], # where
637-
referrer="reprocessing2.start_group_reprocessing",
646+
referrer=referrer,
638647
)["data"][0]["times_seen"]
648+
event_count = sync_count = snuba_count
649+
650+
callsite = "reprocessing2.start_group_reprocessing"
651+
if EAPOccurrencesComparator.should_check_experiment(callsite):
652+
count_end = timezone.now()
653+
eap_count = count_occurrences(
654+
organization=organization,
655+
projects=[project],
656+
start=group_first_seen,
657+
end=count_end,
658+
referrer=referrer,
659+
group_id=group_id,
660+
occurrence_category=OccurrenceCategory.ERROR,
661+
)
662+
event_count = sync_count = EAPOccurrencesComparator.check_and_choose(
663+
control_data=snuba_count,
664+
experimental_data=eap_count,
665+
callsite=callsite,
666+
is_experimental_data_a_null_result=eap_count == 0,
667+
reasonable_match_comparator=lambda snuba, eap: eap <= snuba,
668+
debug_context={
669+
"organization_id": organization.id,
670+
"project_id": project.id,
671+
"group_id": group_id,
672+
"group_first_seen": (
673+
group_first_seen.isoformat() if group_first_seen is not None else None
674+
),
675+
"count_end": count_end.isoformat(),
676+
},
677+
)
639678

640679
sentry_sdk.set_extra("event_count", event_count)
641680

tests/snuba/search/test_eap_occurrences.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import pytest
66

7+
from sentry.search.eap.occurrences.common_queries import count_occurrences
78
from sentry.search.eap.types import EAPResponse, SearchResolverConfig
89
from sentry.search.events.types import SnubaParams
910
from sentry.snuba.occurrences_rpc import OccurrenceCategory, Occurrences
@@ -154,3 +155,89 @@ def test_eap_forwarding_rate_dual_write(self) -> None:
154155
assert row["group_id"] == event.group_id
155156
assert row["level"] == "error"
156157
assert row["title"] == event.title
158+
159+
160+
class CountOccurrencesQueryTest(TestCase, SnubaTestCase, OccurrenceTestCase):
161+
def setUp(self) -> None:
162+
super().setUp()
163+
now = datetime.now()
164+
self.start = now - timedelta(hours=1)
165+
self.end = now + timedelta(hours=1)
166+
self.referrer = "test.occurrences_common_queries"
167+
168+
def test_counts_all_occurrences(self) -> None:
169+
group = self.create_group(project=self.project)
170+
occurrences = [self.create_eap_occurrence(group_id=group.id) for _ in range(3)]
171+
self.store_occurrences(occurrences)
172+
173+
result = count_occurrences(
174+
organization=self.organization,
175+
projects=[self.project],
176+
start=self.start,
177+
end=self.end,
178+
referrer=self.referrer,
179+
)
180+
assert result == 3
181+
182+
def test_filters_by_group_id(self) -> None:
183+
group_1 = self.create_group(project=self.project)
184+
group_2 = self.create_group(project=self.project)
185+
self.store_occurrences(
186+
[
187+
self.create_eap_occurrence(group_id=group_1.id),
188+
self.create_eap_occurrence(group_id=group_2.id),
189+
self.create_eap_occurrence(group_id=group_2.id),
190+
]
191+
)
192+
193+
result_1 = count_occurrences(
194+
organization=self.organization,
195+
projects=[self.project],
196+
start=self.start,
197+
end=self.end,
198+
referrer=self.referrer,
199+
group_id=group_1.id,
200+
)
201+
assert result_1 == 1
202+
203+
result_2 = count_occurrences(
204+
organization=self.organization,
205+
projects=[self.project],
206+
start=self.start,
207+
end=self.end,
208+
referrer=self.referrer,
209+
group_id=group_2.id,
210+
)
211+
assert result_2 == 2
212+
213+
def test_filters_by_occurrence_category(self) -> None:
214+
group = self.create_group(project=self.project)
215+
self.store_occurrences(
216+
[
217+
self.create_eap_occurrence(group_id=group.id, occurrence_type="error"),
218+
self.create_eap_occurrence(group_id=group.id, occurrence_type="error"),
219+
self.create_eap_occurrence(group_id=group.id, occurrence_type="error"),
220+
self.create_eap_occurrence(group_id=group.id, occurrence_type="generic"),
221+
self.create_eap_occurrence(group_id=group.id, occurrence_type="generic"),
222+
]
223+
)
224+
225+
error_count = count_occurrences(
226+
organization=self.organization,
227+
projects=[self.project],
228+
start=self.start,
229+
end=self.end,
230+
referrer=self.referrer,
231+
occurrence_category=OccurrenceCategory.ERROR,
232+
)
233+
generic_count = count_occurrences(
234+
organization=self.organization,
235+
projects=[self.project],
236+
start=self.start,
237+
end=self.end,
238+
referrer=self.referrer,
239+
occurrence_category=OccurrenceCategory.GENERIC,
240+
)
241+
242+
assert error_count == 3
243+
assert generic_count == 2

0 commit comments

Comments
 (0)