From 3e6ccf656a405e09b628998654539bbdcf7234db Mon Sep 17 00:00:00 2001 From: Nar Saynorath Date: Wed, 3 Sep 2025 13:14:52 -0400 Subject: [PATCH 1/2] feat(on-demand): Add feature flag check before cardinality check --- src/sentry/tasks/on_demand_metrics.py | 5 ++++- .../endpoints/test_organization_dashboard_details.py | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sentry/tasks/on_demand_metrics.py b/src/sentry/tasks/on_demand_metrics.py index 6d1c65116a2135..1ee8a6a4f43e4f 100644 --- a/src/sentry/tasks/on_demand_metrics.py +++ b/src/sentry/tasks/on_demand_metrics.py @@ -8,7 +8,7 @@ from celery.exceptions import SoftTimeLimitExceeded from django.utils import timezone -from sentry import options +from sentry import features, options from sentry.models.dashboard_widget import ( DashboardWidgetQuery, DashboardWidgetQueryOnDemand, @@ -423,6 +423,9 @@ def check_field_cardinality( is_task: bool = False, widget_query: DashboardWidgetQuery | None = None, ) -> dict[str, str]: + if not features.has("organizations:on-demand-metrics-extraction-widgets", organization): + return {} + if not query_columns: return {} if is_task: diff --git a/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py b/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py index 8ff5653974a36f..b116e73ec19d70 100644 --- a/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py +++ b/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py @@ -3132,7 +3132,9 @@ def test_ondemand_updates_new_widget(self, mock_query: mock.MagicMock) -> None: assert current_version.extraction_state == "enabled:creation" @mock.patch("sentry.tasks.on_demand_metrics._query_cardinality") - def test_cardinality_precedence_over_feature_checks(self, mock_query: mock.MagicMock) -> None: + def test_feature_check_takes_precedence_over_cardinality( + self, mock_query: mock.MagicMock + ) -> None: mock_query.return_value = {"data": [{"count_unique(sometag)": 1_000_000}]}, [ "sometag", ] @@ -3169,7 +3171,7 @@ def test_cardinality_precedence_over_feature_checks(self, mock_query: mock.Magic for version in OnDemandMetricSpecVersioning.get_spec_versions(): current_version = ondemand_objects.filter(spec_version=version.version).first() assert current_version is not None - assert current_version.extraction_state == "disabled:high-cardinality" + assert current_version.extraction_state == "disabled:pre-rollout" @mock.patch("sentry.api.serializers.rest_framework.dashboard.get_current_widget_specs") def test_cardinality_skips_non_discover_widget_types( From d1ba9ef9542a1cb98274a385edb844947176534c Mon Sep 17 00:00:00 2001 From: Nar Saynorath Date: Mon, 15 Sep 2025 11:50:31 -0400 Subject: [PATCH 2/2] Copy old test for coverage with feature flag --- .../test_organization_dashboard_details.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py b/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py index b116e73ec19d70..f05c31d1b2e742 100644 --- a/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py +++ b/tests/sentry/dashboards/endpoints/test_organization_dashboard_details.py @@ -3131,6 +3131,48 @@ def test_ondemand_updates_new_widget(self, mock_query: mock.MagicMock) -> None: assert current_version is not None assert current_version.extraction_state == "enabled:creation" + @mock.patch("sentry.tasks.on_demand_metrics._query_cardinality") + def test_cardinality_check_with_feature_flag(self, mock_query: mock.MagicMock) -> None: + mock_query.return_value = {"data": [{"count_unique(sometag)": 1_000_000}]}, [ + "sometag", + ] + data: dict[str, Any] = { + "title": "first dashboard", + "widgets": [ + { + "title": "errors per project", + "displayType": "table", + "interval": "5m", + "widgetType": DashboardWidgetTypes.get_type_name(self.widget_type), + "queries": [ + { + "name": "errors", + "fields": ["count()", "sometag"], + "columns": ["sometag"], + "aggregates": ["count()"], + "conditions": "event.type:transaction", + } + ], + }, + ], + } + + with self.feature(["organizations:on-demand-metrics-extraction-widgets"]): + response = self.do_request("put", self.url(self.dashboard.id), data=data) + assert response.status_code == 200, response.data + widgets = self.get_widgets(self.dashboard.id) + assert len(widgets) == 1 + last = list(widgets).pop() + queries = last.dashboardwidgetquery_set.all() + + ondemand_objects = DashboardWidgetQueryOnDemand.objects.filter( + dashboard_widget_query=queries[0] + ) + for version in OnDemandMetricSpecVersioning.get_spec_versions(): + current_version = ondemand_objects.filter(spec_version=version.version).first() + assert current_version is not None + assert current_version.extraction_state == "disabled:high-cardinality" + @mock.patch("sentry.tasks.on_demand_metrics._query_cardinality") def test_feature_check_takes_precedence_over_cardinality( self, mock_query: mock.MagicMock