From c60e9bf61550200c2acdab7195821702b3c75a0c Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 14:38:26 +0000 Subject: [PATCH 1/2] feat(eap): Allow 30 day timeseries granularity Co-Authored-By: Dominik Buszowiecki <44422760+DominikB2014@users.noreply.github.com> --- .../endpoints/organization_issue_timeseries.py | 2 +- src/sentry/search/eap/constants.py | 1 + src/sentry/snuba/snuba_query_validator.py | 8 ++++++-- .../endpoints/test_organization_issue_timeseries.py | 13 +++++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/sentry/issues/endpoints/organization_issue_timeseries.py b/src/sentry/issues/endpoints/organization_issue_timeseries.py index 30ac43c274eb..ef52a1eab6f7 100644 --- a/src/sentry/issues/endpoints/organization_issue_timeseries.py +++ b/src/sentry/issues/endpoints/organization_issue_timeseries.py @@ -303,7 +303,7 @@ def make_timeseries_result( values: list[Row], ) -> TimeSeries: meta = SeriesMeta( - interval=interval.seconds * 1000, + interval=int(interval.total_seconds()) * 1000, valueType="integer", valueUnit=None, ) diff --git a/src/sentry/search/eap/constants.py b/src/sentry/search/eap/constants.py index 67077436a9e2..b8eb15baffec 100644 --- a/src/sentry/search/eap/constants.py +++ b/src/sentry/search/eap/constants.py @@ -184,6 +184,7 @@ 6 * 3600, 12 * 3600, 24 * 3600, # hours + 30 * 24 * 3600, # days } ) TRUTHY_VALUES = {"1", "true"} diff --git a/src/sentry/snuba/snuba_query_validator.py b/src/sentry/snuba/snuba_query_validator.py index 0347ceb8a1bb..c0460ece1ff3 100644 --- a/src/sentry/snuba/snuba_query_validator.py +++ b/src/sentry/snuba/snuba_query_validator.py @@ -54,10 +54,14 @@ CRASH_RATE_ALERTS_ALLOWED_TIME_WINDOWS = [1800, 3600, 7200, 14400, 43200, 86400] MIN_EAP_ALERT_TIME_WINDOW_SECONDS = 300 +# Snuba subscriptions reject time windows longer than a day. +MAX_EAP_ALERT_TIME_WINDOW_SECONDS = 86400 -# Valid time windows for EAP alerts: valid Snuba granularities at or above the alert minimum. +# Valid time windows for EAP alerts: valid Snuba granularities within the alert bounds. EAP_ALERTS_ALLOWED_TIME_WINDOWS = sorted( - g for g in VALID_GRANULARITIES if g >= MIN_EAP_ALERT_TIME_WINDOW_SECONDS + g + for g in VALID_GRANULARITIES + if MIN_EAP_ALERT_TIME_WINDOW_SECONDS <= g <= MAX_EAP_ALERT_TIME_WINDOW_SECONDS ) diff --git a/tests/sentry/issues/endpoints/test_organization_issue_timeseries.py b/tests/sentry/issues/endpoints/test_organization_issue_timeseries.py index 71ee4f26b40e..35d432ed331b 100644 --- a/tests/sentry/issues/endpoints/test_organization_issue_timeseries.py +++ b/tests/sentry/issues/endpoints/test_organization_issue_timeseries.py @@ -191,6 +191,19 @@ def test_get_new_issues(self) -> None: "interval": 3_600_000, } + def test_meta_interval_with_multi_day_interval(self) -> None: + response = self.do_request( + { + "start": self.end - timedelta(days=90), + "end": self.end, + "interval": "30d", + "category": "issue", + "yAxis": "count(new_issues)", + }, + ) + assert response.status_code == 200, response.content + assert response.data["timeSeries"][0]["meta"]["interval"] == 2_592_000_000 + def test_get_resolved_issues(self) -> None: response = self.do_request( { From 509bf42e2b50da6189d2c05a0f647711be55650b Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 14:39:26 +0000 Subject: [PATCH 2/2] fix(uptime): Keep default stats rollup at one day or less Co-Authored-By: Dominik Buszowiecki <44422760+DominikB2014@users.noreply.github.com> --- .../uptime/endpoints/organization_uptime_stats.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sentry/uptime/endpoints/organization_uptime_stats.py b/src/sentry/uptime/endpoints/organization_uptime_stats.py index 3159e40ae8e0..00db2be0a719 100644 --- a/src/sentry/uptime/endpoints/organization_uptime_stats.py +++ b/src/sentry/uptime/endpoints/organization_uptime_stats.py @@ -37,6 +37,9 @@ logger = logging.getLogger(__name__) +# Don't default to the multi-day granularities; they're only used when requested explicitly. +MAX_DEFAULT_ROLLUP_SECONDS = 24 * 3600 + @cell_silo_endpoint @extend_schema(tags=["Uptime Monitors"]) @@ -51,8 +54,12 @@ def get(self, request: Request, organization: Organization) -> Response: timerange_args = self._parse_args(request, restrict_rollups=False) if "resolution" not in request.GET: timerange_args["rollup"] = min( - (g for g in VALID_GRANULARITIES if g >= timerange_args["rollup"]), - default=max(VALID_GRANULARITIES), + ( + g + for g in VALID_GRANULARITIES + if timerange_args["rollup"] <= g <= MAX_DEFAULT_ROLLUP_SECONDS + ), + default=MAX_DEFAULT_ROLLUP_SECONDS, ) rollup_error = self._validate_rollup(timerange_args) if rollup_error: