Browse Source

ref(releasehealth): Implement check_releases_have_health_data on metrics backend [INGEST-249] (#28823)

Implement metrics version for check_releases_have_health_data [INGEST-249]
Radu Woinaroski 3 years ago
parent
commit
f619395116

+ 2 - 3
src/sentry/api/endpoints/organization_releases.py

@@ -6,7 +6,7 @@ from django.db.models import F, Q
 from rest_framework.exceptions import ParseError
 from rest_framework.response import Response
 
-from sentry import analytics, features
+from sentry import analytics, features, releasehealth
 from sentry.api.base import EnvironmentMixin, ReleaseAnalyticsMixin
 from sentry.api.bases import NoProjects
 from sentry.api.bases.organization import OrganizationReleasesBaseEndpoint
@@ -42,7 +42,6 @@ from sentry.search.events.filter import handle_negation, parse_semver
 from sentry.signals import release_created
 from sentry.snuba.sessions import (
     STATS_PERIODS,
-    check_releases_have_health_data,
     get_changed_project_release_model_adoptions,
     get_oldest_health_data_for_releases,
     get_project_releases_by_stability,
@@ -326,7 +325,7 @@ class OrganizationReleasesEndpoint(
                         : total_offset + limit
                     ]
                 )
-                releases_with_session_data = check_releases_have_health_data(
+                releases_with_session_data = releasehealth.check_releases_have_health_data(
                     organization.id,
                     filter_params["project_id"],
                     release_versions,

+ 15 - 0
src/sentry/releasehealth/base.py

@@ -30,6 +30,7 @@ class ReleaseHealthBackend(Service):  # type: ignore
         "get_current_and_previous_crash_free_rates",
         "get_release_adoption",
         "check_has_health_data",
+        "check_releases_have_health_data",
     )
 
     def get_current_and_previous_crash_free_rates(
@@ -123,3 +124,17 @@ class ReleaseHealthBackend(Service):  # type: ignore
             release)
         """
         raise NotImplementedError()
+
+    def check_releases_have_health_data(
+        self,
+        organization_id: OrganizationId,
+        project_ids: Sequence[ProjectId],
+        release_versions: Sequence[ReleaseName],
+        start: datetime,
+        end: datetime,
+    ) -> Set[ReleaseName]:
+
+        """
+        Returns a set of all release versions that have health data within a given period of time.
+        """
+        raise NotImplementedError()

+ 44 - 9
src/sentry/releasehealth/metrics.py

@@ -386,16 +386,10 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
             where_clause.append(Condition(Column(release_column_name), Op.IN, releases_ids))
             column_names = ["project_id", release_column_name]
 
-            # def extract_raw_info(row: Mapping[str, Union[int, str]]) -> ProjectOrRelease:
-            #     return row["project_id"], reverse_tag_value(org_id, row.get(release_column_name))  # type: ignore
-
         else:
             column_names = ["project_id"]
 
-            # def extract_raw_info(row: Mapping[str, Union[int, str]]) -> ProjectOrRelease:
-            #     return row["project_id"]  # type: ignore
-
-        def extract_raw_info_func(
+        def extract_row_info_func(
             include_releases: bool,
         ) -> Callable[[Mapping[str, Union[int, str]]], ProjectOrRelease]:
             def f(row: Mapping[str, Union[int, str]]) -> ProjectOrRelease:
@@ -406,7 +400,7 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
 
             return f
 
-        extract_raw_info = extract_raw_info_func(includes_releases)
+        extract_row_info = extract_row_info_func(includes_releases)
 
         query_cols = [Column(column_name) for column_name in column_names]
         group_by_clause = query_cols
@@ -423,4 +417,45 @@ class MetricsReleaseHealthBackend(ReleaseHealthBackend):
             query, referrer="releasehealth.metrics.check_has_health_data", use_cache=False
         )
 
-        return {extract_raw_info(raw) for raw in result["data"]}
+        return {extract_row_info(row) for row in result["data"]}
+
+    def check_releases_have_health_data(
+        self,
+        organization_id: OrganizationId,
+        project_ids: Sequence[ProjectId],
+        release_versions: Sequence[ReleaseName],
+        start: datetime,
+        end: datetime,
+    ) -> Set[ReleaseName]:
+
+        release_column_name = tag_key(organization_id, "release")
+        releases_ids = [
+            release_id
+            for release_id in [
+                try_get_tag_value(organization_id, release) for release in release_versions
+            ]
+            if release_id is not None
+        ]
+        query = Query(
+            dataset=Dataset.Metrics.value,
+            match=Entity("metrics_counters"),
+            select=[Column(release_column_name)],
+            where=[
+                Condition(Column("org_id"), Op.EQ, organization_id),
+                Condition(Column("project_id"), Op.IN, project_ids),
+                Condition(Column("metric_id"), Op.EQ, metric_id(organization_id, "session")),
+                Condition(Column(release_column_name), Op.IN, releases_ids),
+                Condition(Column("timestamp"), Op.GTE, start),
+                Condition(Column("timestamp"), Op.LT, end),
+            ],
+            groupby=[Column(release_column_name)],
+        )
+
+        result = raw_snql_query(
+            query, referrer="releasehealth.metrics.check_releases_have_health_data", use_cache=False
+        )
+
+        def extract_row_info(row: Mapping[str, Union[OrganizationId, str]]) -> ReleaseName:
+            return reverse_tag_value(organization_id, row.get(release_column_name))  # type: ignore
+
+        return {extract_row_info(row) for row in result["data"]}

+ 17 - 0
src/sentry/releasehealth/sessions.py

@@ -12,6 +12,7 @@ from sentry.releasehealth.base import (
 )
 from sentry.snuba.sessions import (
     _check_has_health_data,
+    _check_releases_have_health_data,
     _get_release_adoption,
     get_current_and_previous_crash_free_rates,
 )
@@ -54,3 +55,19 @@ class SessionsReleaseHealthBackend(ReleaseHealthBackend):
         self, projects_list: Sequence[ProjectOrRelease]
     ) -> Set[ProjectOrRelease]:
         return _check_has_health_data(projects_list)  # type: ignore
+
+    def check_releases_have_health_data(
+        self,
+        organization_id: OrganizationId,
+        project_ids: Sequence[ProjectId],
+        release_versions: Sequence[ReleaseName],
+        start: datetime,
+        end: datetime,
+    ) -> Set[ReleaseName]:
+        return _check_releases_have_health_data(  # type: ignore
+            organization_id,
+            project_ids,
+            release_versions,
+            start,
+            end,
+        )

+ 2 - 4
src/sentry/snuba/sessions.py

@@ -150,7 +150,7 @@ def _check_has_health_data(projects_list):
     return {data_tuple(x) for x in raw_query(**raw_query_args)["data"]}
 
 
-def check_releases_have_health_data(
+def _check_releases_have_health_data(
     organization_id: int,
     project_ids: List[int],
     release_versions: List[str],
@@ -274,9 +274,7 @@ def get_project_releases_count(
         where=where,
         having=having,
     )
-    data = snuba.raw_snql_query(query, referrer="snuba.sessions.check_releases_have_health_data")[
-        "data"
-    ]
+    data = snuba.raw_snql_query(query, referrer="snuba.sessions.get_project_releases_count")["data"]
     return data[0]["count"] if data else 0
 
 

+ 4 - 0
src/sentry/testutils/cases.py

@@ -971,6 +971,10 @@ class SessionMetricsTestCase(SnubaTestCase):
         if status != "ok":  # terminal
             self._push_metric(session, "distribution", "session.duration", {}, session["duration"])
 
+    def bulk_store_sessions(self, sessions):
+        for session in sessions:
+            self.store_session(session)
+
     @classmethod
     def _push_metric(cls, session, type, name, tags, value):
         def metric_id(name):

+ 12 - 3
tests/snuba/sessions/test_sessions.py

@@ -9,7 +9,6 @@ from sentry.releasehealth.metrics import MetricsReleaseHealthBackend
 from sentry.releasehealth.sessions import SessionsReleaseHealthBackend
 from sentry.snuba.sessions import (
     _make_stats,
-    check_releases_have_health_data,
     get_adjacent_releases_based_on_adoption,
     get_oldest_health_data_for_releases,
     get_project_releases_by_stability,
@@ -568,7 +567,7 @@ class SnubaSessionsTest(TestCase, SnubaTestCase):
 
 class SnubaSessionsTestMetrics(ReleaseHealthMetricsTestCase, SnubaSessionsTest):
     """
-    Same tests as in SnunbaSessionsTest but using the Metrics backendx
+    Same tests as in SnunbaSessionsTest but using the Metrics backend
     """
 
     pass
@@ -1853,13 +1852,15 @@ class GetProjectReleasesCountTest(TestCase, SnubaTestCase):
 
 
 class CheckReleasesHaveHealthDataTest(TestCase, SnubaTestCase):
+    backend = SessionsReleaseHealthBackend()
+
     def run_test(self, expected, projects, releases, start=None, end=None):
         if not start:
             start = datetime.now() - timedelta(days=1)
         if not end:
             end = datetime.now()
         assert (
-            check_releases_have_health_data(
+            self.backend.check_releases_have_health_data(
                 self.organization.id,
                 [p.id for p in projects],
                 [r.version for r in releases],
@@ -1892,3 +1893,11 @@ class CheckReleasesHaveHealthDataTest(TestCase, SnubaTestCase):
         self.run_test([release_1], [other_project], [release_1])
         self.run_test([release_1, release_2], [other_project], [release_1, release_2])
         self.run_test([release_1, release_2], [self.project, other_project], [release_1, release_2])
+
+
+class CheckReleasesHaveHealthDataTestMetrics(
+    ReleaseHealthMetricsTestCase, CheckReleasesHaveHealthDataTest
+):
+    """Repeat tests with metrics backend"""
+
+    pass