Browse Source

fix(discover) Fix pagination link generation with invalid dates (#15750)

If an aggregate of events had its most recent event happen 14 days ago,
and then the user views the event-details page. They can then change the
global selection header date range to be 24h. This results in invalid
date conditions being generated for the pagination link queries as the
end and start ranges will be inverted. We should ignore this error and
not 500 as the user has created an impossible query condition and there
isn't a real problem.

Fixes SENTRY-D7P
Mark Story 5 years ago
parent
commit
9c1c3038b7

+ 16 - 11
src/sentry/eventstore/snuba/backend.py

@@ -148,17 +148,22 @@ class SnubaEventStorage(EventStorage):
 
     def __get_event_id_from_filter(self, filter=None, orderby=None):
         columns = ["event_id", "project_id"]
-        result = snuba.dataset_query(
-            selected_columns=columns,
-            conditions=filter.conditions,
-            filter_keys=filter.filter_keys,
-            start=filter.start,
-            end=filter.end,
-            limit=1,
-            referrer="eventstore.get_next_or_prev_event_id",
-            orderby=orderby,
-            dataset=snuba.detect_dataset({"conditions": filter.conditions}),
-        )
+        try:
+            result = snuba.dataset_query(
+                selected_columns=columns,
+                conditions=filter.conditions,
+                filter_keys=filter.filter_keys,
+                start=filter.start,
+                end=filter.end,
+                limit=1,
+                referrer="eventstore.get_next_or_prev_event_id",
+                orderby=orderby,
+                dataset=snuba.detect_dataset({"conditions": filter.conditions}),
+            )
+        except (snuba.QueryOutsideRetentionError, snuba.QueryOutsideGroupActivityError):
+            # This can happen when the date conditions for paging
+            # and the current event generate impossible conditions.
+            return None
 
         if "error" in result or len(result["data"]) == 0:
             return None

+ 16 - 11
src/sentry/eventstore/snuba_discover/backend.py

@@ -78,17 +78,22 @@ class SnubaDiscoverEventStorage(EventStorage):
 
     def __get_event_id_from_filter(self, filter=None, orderby=None):
         columns = ["event_id", "project_id", "timestamp"]
-        result = snuba.raw_query(
-            selected_columns=columns,
-            conditions=filter.conditions,
-            filter_keys=filter.filter_keys,
-            start=filter.start,
-            end=filter.end,
-            limit=1,
-            referrer="eventstore.discover_dataset.get_next_or_prev_event_id",
-            orderby=orderby,
-            dataset=snuba.Dataset.Discover,
-        )
+        try:
+            result = snuba.raw_query(
+                selected_columns=columns,
+                conditions=filter.conditions,
+                filter_keys=filter.filter_keys,
+                start=filter.start,
+                end=filter.end,
+                limit=1,
+                referrer="eventstore.discover_dataset.get_next_or_prev_event_id",
+                orderby=orderby,
+                dataset=snuba.Dataset.Discover,
+            )
+        except (snuba.QueryOutsideRetentionError, snuba.QueryOutsideGroupActivityError):
+            # This can happen when the date conditions for paging
+            # and the current event generate impossible conditions.
+            return None
 
         if "error" in result or len(result["data"]) == 0:
             return None

+ 34 - 0
tests/snuba/api/endpoints/test_organization_event_details.py

@@ -66,6 +66,40 @@ class OrganizationEventDetailsEndpointTest(APITestCase, SnubaTestCase):
         assert response.data["nextEventID"] == "b" * 32
         assert response.data["projectSlug"] == self.project.slug
 
+    def test_simple_out_of_range_pagination(self):
+        two_weeks_ago = iso_format(before_now(days=14))
+        self.store_event(
+            data={
+                "event_id": "d" * 32,
+                "message": "very old, very bad",
+                "timestamp": two_weeks_ago,
+                "fingerprint": ["group-3"],
+            },
+            project_id=self.project.id,
+        )
+        url = reverse(
+            "sentry-api-0-organization-event-details",
+            kwargs={
+                "organization_slug": self.project.organization.slug,
+                "project_slug": self.project.slug,
+                "event_id": "d" * 32,
+            },
+        )
+
+        with self.feature("organizations:events-v2"):
+            response = self.client.get(
+                url,
+                data={"field": ["title", "count_unique(user)"], "statsPeriod": "24h"},
+                format="json",
+            )
+
+        assert response.status_code == 200, response.content
+        assert response.data["id"] == "d" * 32
+        assert response.data["previousEventID"] is None
+        assert response.data["nextEventID"] is None
+        assert response.data["latestEventID"] is None
+        assert response.data["oldestEventID"] is None
+
     def test_simple_transaction(self):
         min_ago = iso_format(before_now(minutes=1))
         event = self.store_event(