From 20d6c8d01669d9067f710fe35d11413190aaba0b Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Fri, 6 Jun 2025 15:58:22 -0700 Subject: [PATCH 01/10] Update sentry_app queries to use the read replica --- src/sentry/sentry_apps/services/app/impl.py | 146 ++++++++++++++------ 1 file changed, 101 insertions(+), 45 deletions(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index 6c71a1d5517ee3..a7c57c284e734d 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -4,6 +4,7 @@ from collections.abc import Callable, Mapping from typing import Any +from django.db import router from django.db.models import Q, QuerySet from sentry.api.serializers import Serializer, serialize @@ -51,30 +52,42 @@ def serialize_many( as_user: RpcUser | None = None, auth_context: AuthenticationContext | None = None, ) -> list[OpaqueSerializedResponse]: - return self._FQ.serialize_many(filter, as_user, auth_context) + query = self._FQ.base_query().using(router.db_for_read(SentryAppInstallation, replica=True)) + query = self._FQ.apply_filters(query, filter) + return [self._FQ.serialize_rpc(install) for install in query] def get_many( self, *, filter: SentryAppInstallationFilterArgs ) -> list[RpcSentryAppInstallation]: - return self._FQ.get_many(filter) + query = self._FQ.base_query().using(router.db_for_read(SentryAppInstallation, replica=True)) + query = self._FQ.apply_filters(query, filter) + return [self._FQ.serialize_rpc(install) for install in query] def find_app_components(self, *, app_id: int) -> list[RpcSentryAppComponent]: return [ serialize_sentry_app_component(c) - for c in SentryAppComponent.objects.filter(sentry_app_id=app_id) + for c in SentryAppComponent.objects.using( + router.db_for_read(SentryAppComponent, replica=True) + ).filter(sentry_app_id=app_id) ] def get_sentry_app_by_id(self, *, id: int) -> RpcSentryApp | None: try: - sentry_app = SentryApp.objects.get(id=id) + sentry_app = SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)).get( + id=id + ) except SentryApp.DoesNotExist: return None return serialize_sentry_app(sentry_app) def get_installation_by_id(self, *, id: int) -> RpcSentryAppInstallation | None: try: - install = SentryAppInstallation.objects.select_related("sentry_app").get( - id=id, status=SentryAppInstallationStatus.INSTALLED + install = ( + SentryAppInstallation.objects.using( + router.db_for_read(SentryAppInstallation, replica=True) + ) + .select_related("sentry_app") + .get(id=id, status=SentryAppInstallationStatus.INSTALLED) ) return serialize_sentry_app_installation(install) except SentryAppInstallation.DoesNotExist: @@ -85,7 +98,12 @@ def get_installation_org_id_by_token_id(self, token_id: int) -> int | None: "status": SentryAppInstallationStatus.INSTALLED, "api_installation_token_id": str(token_id), } - queryset = self._FQ.apply_filters(SentryAppInstallation.objects.all(), filters) + queryset = self._FQ.apply_filters( + SentryAppInstallation.objects.using( + router.db_for_read(SentryAppInstallation, replica=True) + ).all(), + filters, + ) install = queryset.first() if not install: return None @@ -93,7 +111,9 @@ def get_installation_org_id_by_token_id(self, token_id: int) -> int | None: def get_sentry_app_by_slug(self, *, slug: str) -> RpcSentryApp | None: try: - sentry_app = SentryApp.objects.get(slug=slug) + sentry_app = SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)).get( + slug=slug + ) return serialize_sentry_app(sentry_app) except SentryApp.DoesNotExist: return None @@ -101,23 +121,35 @@ def get_sentry_app_by_slug(self, *, slug: str) -> RpcSentryApp | None: def get_installations_for_organization( self, *, organization_id: int ) -> list[RpcSentryAppInstallation]: - installations = SentryAppInstallation.objects.get_installed_for_organization( - organization_id - ).select_related("sentry_app", "api_token") + installations = ( + SentryAppInstallation.objects.using( + router.db_for_read(SentryAppInstallation, replica=True) + ) + .get_installed_for_organization(organization_id) + .select_related("sentry_app", "api_token") + ) fq = self._AppServiceFilterQuery() return [fq.serialize_rpc(i) for i in installations] def find_alertable_services(self, *, organization_id: int) -> list[RpcSentryAppService]: result: list[RpcSentryAppService] = [] - for app in SentryApp.objects.filter( - installations__organization_id=organization_id, - is_alertable=True, - installations__status=SentryAppInstallationStatus.INSTALLED, - installations__date_deleted=None, - ).distinct("id"): - if SentryAppComponent.objects.filter( - sentry_app_id=app.id, type="alert-rule-action" - ).exists(): + for app in ( + SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)) + .filter( + installations__organization_id=organization_id, + is_alertable=True, + installations__status=SentryAppInstallationStatus.INSTALLED, + installations__date_deleted=None, + ) + .distinct("id") + ): + if ( + SentryAppComponent.objects.using( + router.db_for_read(SentryAppComponent, replica=True) + ) + .filter(sentry_app_id=app.id, type="alert-rule-action") + .exists() + ): continue result.append( RpcSentryAppService( @@ -131,9 +163,9 @@ def get_custom_alert_rule_actions( self, *, event_data: RpcSentryAppEventData, organization_id: int, project_slug: str | None ) -> list[Mapping[str, Any]]: action_list = [] - for install in SentryAppInstallation.objects.get_installed_for_organization( - organization_id - ): + for install in SentryAppInstallation.objects.using( + router.db_for_read(SentryAppInstallation, replica=True) + ).get_installed_for_organization(organization_id): component = prepare_sentry_app_components(install, "alert-rule-action", project_slug) if component: kwargs = { @@ -150,14 +182,17 @@ def get_custom_alert_rule_actions( def get_component_contexts( self, *, filter: SentryAppInstallationFilterArgs, component_type: str ) -> list[RpcSentryAppComponentContext]: - install_query = self._FQ.query_many(filter=filter) + install_query = self._FQ.base_query().using( + router.db_for_read(SentryAppInstallation, replica=True) + ) + install_query = self._FQ.apply_filters(install_query, filter) install_query = install_query.select_related("sentry_app", "sentry_app__application") install_map: dict[int, list[SentryAppInstallation]] = defaultdict(list) for install in install_query: install_map[install.sentry_app_id].append(install) - component_query = SentryAppComponent.objects.filter( - type=component_type, sentry_app_id__in=list(install_map.keys()) - ) + component_query = SentryAppComponent.objects.using( + router.db_for_read(SentryAppComponent, replica=True) + ).filter(type=component_type, sentry_app_id__in=list(install_map.keys())) output = [] for component in component_query: installs = install_map[component.sentry_app_id] @@ -178,12 +213,15 @@ def get_installation_component_contexts( component_type: str, include_contexts_without_component: bool = False, ) -> list[RpcSentryAppComponentContext]: - install_query = self._FQ.query_many(filter=filter) + install_query = self._FQ.base_query().using( + router.db_for_read(SentryAppInstallation, replica=True) + ) + install_query = self._FQ.apply_filters(install_query, filter) app_ids = install_query.values_list("sentry_app_id", flat=True) - component_query = SentryAppComponent.objects.filter( - type=component_type, sentry_app_id__in=list(app_ids) - ) + component_query = SentryAppComponent.objects.using( + router.db_for_read(SentryAppComponent, replica=True) + ).filter(type=component_type, sentry_app_id__in=list(app_ids)) component_map: dict[int, SentryAppComponent] = {} output = [] @@ -248,9 +286,15 @@ def apply_filters( # Internal Integrations follow this pattern because they can have multiple tokens. # Decompose this query instead of using a subquery for performance. - install_token_list = SentryAppInstallationToken.objects.filter( - api_token_id=filters["api_installation_token_id"], - ).values_list("sentry_app_installation_id", flat=True) + install_token_list = ( + SentryAppInstallationToken.objects.using( + router.db_for_read(SentryAppInstallationToken, replica=True) + ) + .filter( + api_token_id=filters["api_installation_token_id"], + ) + .values_list("sentry_app_installation_id", flat=True) + ) query = query.filter( Q(api_token_id=filters["api_installation_token_id"]) @@ -268,21 +312,25 @@ def find_installation_by_proxy_user( self, *, proxy_user_id: int, organization_id: int ) -> RpcSentryAppInstallation | None: try: - sentry_app = SentryApp.objects.get(proxy_user_id=proxy_user_id) + sentry_app = SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)).get( + proxy_user_id=proxy_user_id + ) except SentryApp.DoesNotExist: return None try: - installation = SentryAppInstallation.objects.get( - sentry_app_id=sentry_app.id, organization_id=organization_id - ) + installation = SentryAppInstallation.objects.using( + router.db_for_read(SentryAppInstallation, replica=True) + ).get(sentry_app_id=sentry_app.id, organization_id=organization_id) except SentryAppInstallation.DoesNotExist: return None return serialize_sentry_app_installation(installation, sentry_app) def get_installation_token(self, *, organization_id: int, provider: str) -> str | None: - return SentryAppInstallationToken.objects.get_token(organization_id, provider) + return SentryAppInstallationToken.objects.using( + router.db_for_read(SentryAppInstallationToken, replica=True) + ).get_token(organization_id, provider) def trigger_sentry_app_action_creators( self, *, fields: list[Mapping[str, Any]], install_uuid: str | None @@ -308,16 +356,20 @@ def trigger_sentry_app_action_creators( def find_service_hook_sentry_app(self, *, api_application_id: int) -> RpcSentryApp | None: try: - return serialize_sentry_app(SentryApp.objects.get(application_id=api_application_id)) + return serialize_sentry_app( + SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)).get( + application_id=api_application_id + ) + ) except SentryApp.DoesNotExist: return None def get_published_sentry_apps_for_organization( self, *, organization_id: int ) -> list[RpcSentryApp]: - published_apps = SentryApp.objects.filter( - owner_id=organization_id, status=SentryAppStatus.PUBLISHED - ) + published_apps = SentryApp.objects.using( + router.db_for_read(SentryApp, replica=True) + ).filter(owner_id=organization_id, status=SentryAppStatus.PUBLISHED) return [serialize_sentry_app(app) for app in published_apps] def get_internal_integrations( @@ -337,7 +389,9 @@ def get_internal_integrations( list[RpcSentryApp]: A list of serialized internal Sentry Apps matching the criteria. Returns an empty list if no matches are found. """ - internal_integrations = SentryApp.objects.filter( + internal_integrations = SentryApp.objects.using( + router.db_for_read(SentryApp, replica=True) + ).filter( owner_id=organization_id, status=SentryAppStatus.INTERNAL, name=integration_name, @@ -384,7 +438,9 @@ def prepare_sentry_app_components( ) -> RpcSentryAppComponent | None: from sentry.sentry_apps.models.sentry_app_installation import prepare_sentry_app_components - installation = SentryAppInstallation.objects.get(id=installation_id) + installation = SentryAppInstallation.objects.using( + router.db_for_read(SentryAppInstallation, replica=True) + ).get(id=installation_id) component = prepare_sentry_app_components(installation, component_type, project_slug) return serialize_sentry_app_component(component) if component else None From c568ec1d85861a54e09d4beac921049cc65997f5 Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Mon, 9 Jun 2025 14:51:43 -0700 Subject: [PATCH 02/10] updatet to using_replica --- src/sentry/sentry_apps/services/app/impl.py | 86 ++++++++------------- 1 file changed, 31 insertions(+), 55 deletions(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index 7fcd67895106c8..5db6bcf4624681 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -62,16 +62,12 @@ def get_many( def find_app_components(self, *, app_id: int) -> list[RpcSentryAppComponent]: return [ serialize_sentry_app_component(c) - for c in SentryAppComponent.objects.using( - router.db_for_read(SentryAppComponent, replica=True) - ).filter(sentry_app_id=app_id) + for c in SentryAppComponent.objects.using_replica().filter(sentry_app_id=app_id) ] def get_sentry_app_by_id(self, *, id: int) -> RpcSentryApp | None: try: - sentry_app = SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)).get( - id=id - ) + sentry_app = SentryApp.objects.using_replica().get(id=id) except SentryApp.DoesNotExist: return None return serialize_sentry_app(sentry_app) @@ -79,9 +75,7 @@ def get_sentry_app_by_id(self, *, id: int) -> RpcSentryApp | None: def get_installation_by_id(self, *, id: int) -> RpcSentryAppInstallation | None: try: install = ( - SentryAppInstallation.objects.using( - router.db_for_read(SentryAppInstallation, replica=True) - ) + SentryAppInstallation.objects.using_replica() .select_related("sentry_app") .get(id=id, status=SentryAppInstallationStatus.INSTALLED) ) @@ -95,9 +89,7 @@ def get_installation_org_id_by_token_id(self, token_id: int) -> int | None: "api_installation_token_id": str(token_id), } queryset = self._FQ.apply_filters( - SentryAppInstallation.objects.using( - router.db_for_read(SentryAppInstallation, replica=True) - ).all(), + SentryAppInstallation.objects.using_replica().all(), filters, ) install = queryset.first() @@ -107,9 +99,7 @@ def get_installation_org_id_by_token_id(self, token_id: int) -> int | None: def get_sentry_app_by_slug(self, *, slug: str) -> RpcSentryApp | None: try: - sentry_app = SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)).get( - slug=slug - ) + sentry_app = SentryApp.objects.using_replica().get(slug=slug) return serialize_sentry_app(sentry_app) except SentryApp.DoesNotExist: return None @@ -118,9 +108,7 @@ def get_installations_for_organization( self, *, organization_id: int ) -> list[RpcSentryAppInstallation]: installations = ( - SentryAppInstallation.objects.using( - router.db_for_read(SentryAppInstallation, replica=True) - ) + SentryAppInstallation.objects.using_replica() .get_installed_for_organization(organization_id) .select_related("sentry_app", "api_token") ) @@ -130,7 +118,7 @@ def get_installations_for_organization( def find_alertable_services(self, *, organization_id: int) -> list[RpcSentryAppService]: result: list[RpcSentryAppService] = [] for app in ( - SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)) + SentryApp.objects.using_replica() .filter( installations__organization_id=organization_id, is_alertable=True, @@ -140,9 +128,7 @@ def find_alertable_services(self, *, organization_id: int) -> list[RpcSentryAppS .distinct("id") ): if ( - SentryAppComponent.objects.using( - router.db_for_read(SentryAppComponent, replica=True) - ) + SentryAppComponent.objects.using_replica() .filter(sentry_app_id=app.id, type="alert-rule-action") .exists() ): @@ -159,9 +145,9 @@ def get_custom_alert_rule_actions( self, *, event_data: RpcSentryAppEventData, organization_id: int, project_slug: str | None ) -> list[Mapping[str, Any]]: action_list = [] - for install in SentryAppInstallation.objects.using( - router.db_for_read(SentryAppInstallation, replica=True) - ).get_installed_for_organization(organization_id): + for install in SentryAppInstallation.objects.get_installed_for_organization( + organization_id + ): component = prepare_sentry_app_components(install, "alert-rule-action", project_slug) if component: kwargs = { @@ -178,17 +164,15 @@ def get_custom_alert_rule_actions( def get_component_contexts( self, *, filter: SentryAppInstallationFilterArgs, component_type: str ) -> list[RpcSentryAppComponentContext]: - install_query = self._FQ.base_query().using( - router.db_for_read(SentryAppInstallation, replica=True) - ) + install_query = self._FQ.base_query().using_replica() install_query = self._FQ.apply_filters(install_query, filter) install_query = install_query.select_related("sentry_app", "sentry_app__application") install_map: dict[int, list[SentryAppInstallation]] = defaultdict(list) for install in install_query: install_map[install.sentry_app_id].append(install) - component_query = SentryAppComponent.objects.using( - router.db_for_read(SentryAppComponent, replica=True) - ).filter(type=component_type, sentry_app_id__in=list(install_map.keys())) + component_query = SentryAppComponent.objects.using_replica().filter( + type=component_type, sentry_app_id__in=list(install_map.keys()) + ) output = [] for component in component_query: installs = install_map[component.sentry_app_id] @@ -215,9 +199,9 @@ def get_installation_component_contexts( install_query = self._FQ.apply_filters(install_query, filter) app_ids = install_query.values_list("sentry_app_id", flat=True) - component_query = SentryAppComponent.objects.using( - router.db_for_read(SentryAppComponent, replica=True) - ).filter(type=component_type, sentry_app_id__in=list(app_ids)) + component_query = SentryAppComponent.objects.using_replica().filter( + type=component_type, sentry_app_id__in=list(app_ids) + ) component_map: dict[int, SentryAppComponent] = {} output = [] @@ -283,9 +267,7 @@ def apply_filters( # Decompose this query instead of using a subquery for performance. install_token_list = ( - SentryAppInstallationToken.objects.using( - router.db_for_read(SentryAppInstallationToken, replica=True) - ) + SentryAppInstallationToken.objects.using_replica() .filter( api_token_id=filters["api_installation_token_id"], ) @@ -308,25 +290,23 @@ def find_installation_by_proxy_user( self, *, proxy_user_id: int, organization_id: int ) -> RpcSentryAppInstallation | None: try: - sentry_app = SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)).get( - proxy_user_id=proxy_user_id - ) + sentry_app = SentryApp.objects.using_replica().get(proxy_user_id=proxy_user_id) except SentryApp.DoesNotExist: return None try: - installation = SentryAppInstallation.objects.using( - router.db_for_read(SentryAppInstallation, replica=True) - ).get(sentry_app_id=sentry_app.id, organization_id=organization_id) + installation = SentryAppInstallation.objects.using_replica().get( + sentry_app_id=sentry_app.id, organization_id=organization_id + ) except SentryAppInstallation.DoesNotExist: return None return serialize_sentry_app_installation(installation, sentry_app) def get_installation_token(self, *, organization_id: int, provider: str) -> str | None: - return SentryAppInstallationToken.objects.using( - router.db_for_read(SentryAppInstallationToken, replica=True) - ).get_token(organization_id, provider) + return SentryAppInstallationToken.objects.using_replica().get_token( + organization_id, provider + ) def trigger_sentry_app_action_creators( self, *, fields: list[Mapping[str, Any]], install_uuid: str | None @@ -353,9 +333,7 @@ def trigger_sentry_app_action_creators( def find_service_hook_sentry_app(self, *, api_application_id: int) -> RpcSentryApp | None: try: return serialize_sentry_app( - SentryApp.objects.using(router.db_for_read(SentryApp, replica=True)).get( - application_id=api_application_id - ) + SentryApp.objects.using_replica().get(application_id=api_application_id) ) except SentryApp.DoesNotExist: return None @@ -363,9 +341,9 @@ def find_service_hook_sentry_app(self, *, api_application_id: int) -> RpcSentryA def get_published_sentry_apps_for_organization( self, *, organization_id: int ) -> list[RpcSentryApp]: - published_apps = SentryApp.objects.using( - router.db_for_read(SentryApp, replica=True) - ).filter(owner_id=organization_id, status=SentryAppStatus.PUBLISHED) + published_apps = SentryApp.objects.using_replica().filter( + owner_id=organization_id, status=SentryAppStatus.PUBLISHED + ) return [serialize_sentry_app(app) for app in published_apps] def get_internal_integrations( @@ -385,9 +363,7 @@ def get_internal_integrations( list[RpcSentryApp]: A list of serialized internal Sentry Apps matching the criteria. Returns an empty list if no matches are found. """ - internal_integrations = SentryApp.objects.using( - router.db_for_read(SentryApp, replica=True) - ).filter( + internal_integrations = SentryApp.objects.using_replica().filter( owner_id=organization_id, status=SentryAppStatus.INTERNAL, name=integration_name, From 08e66dde6c159f0203abcf3bd8e01e9480827b0f Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Mon, 9 Jun 2025 14:53:09 -0700 Subject: [PATCH 03/10] few more --- src/sentry/sentry_apps/services/app/impl.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index 5db6bcf4624681..92fea8968fd81c 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -4,7 +4,6 @@ from collections.abc import Callable, Mapping from typing import Any -from django.db import router from django.db.models import Q, QuerySet from sentry.api.serializers import Serializer, serialize @@ -193,9 +192,7 @@ def get_installation_component_contexts( component_type: str, include_contexts_without_component: bool = False, ) -> list[RpcSentryAppComponentContext]: - install_query = self._FQ.base_query().using( - router.db_for_read(SentryAppInstallation, replica=True) - ) + install_query = self._FQ.base_query().using_replica() install_query = self._FQ.apply_filters(install_query, filter) app_ids = install_query.values_list("sentry_app_id", flat=True) @@ -410,9 +407,7 @@ def prepare_sentry_app_components( ) -> RpcSentryAppComponent | None: from sentry.sentry_apps.models.sentry_app_installation import prepare_sentry_app_components - installation = SentryAppInstallation.objects.using( - router.db_for_read(SentryAppInstallation, replica=True) - ).get(id=installation_id) + installation = SentryAppInstallation.objects.using_replica().get(id=installation_id) component = prepare_sentry_app_components(installation, component_type, project_slug) return serialize_sentry_app_component(component) if component else None From 3ee736d786c63c786c1e7a62889bfeaeb1e4965a Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Tue, 10 Jun 2025 14:36:16 -0700 Subject: [PATCH 04/10] fix the order because manager vs queryset thing --- src/sentry/sentry_apps/services/app/impl.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index 92fea8968fd81c..2c837d5f9978fa 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -107,8 +107,8 @@ def get_installations_for_organization( self, *, organization_id: int ) -> list[RpcSentryAppInstallation]: installations = ( - SentryAppInstallation.objects.using_replica() - .get_installed_for_organization(organization_id) + SentryAppInstallation.objects.get_installed_for_organization(organization_id) + .using_replica() .select_related("sentry_app", "api_token") ) fq = self._AppServiceFilterQuery() @@ -301,9 +301,9 @@ def find_installation_by_proxy_user( return serialize_sentry_app_installation(installation, sentry_app) def get_installation_token(self, *, organization_id: int, provider: str) -> str | None: - return SentryAppInstallationToken.objects.using_replica().get_token( + return SentryAppInstallationToken.objects.get_token( organization_id, provider - ) + ).using_replica() def trigger_sentry_app_action_creators( self, *, fields: list[Mapping[str, Any]], install_uuid: str | None From 23081fecb0650801c8d26240d535d6d1eb1a1ea9 Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Tue, 10 Jun 2025 14:53:04 -0700 Subject: [PATCH 05/10] a couple more --- src/sentry/sentry_apps/services/app/impl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index 2c837d5f9978fa..0701b077915b80 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -301,15 +301,15 @@ def find_installation_by_proxy_user( return serialize_sentry_app_installation(installation, sentry_app) def get_installation_token(self, *, organization_id: int, provider: str) -> str | None: - return SentryAppInstallationToken.objects.get_token( + return SentryAppInstallationToken.objects.using_replica().get_token( organization_id, provider - ).using_replica() + ) def trigger_sentry_app_action_creators( self, *, fields: list[Mapping[str, Any]], install_uuid: str | None ) -> RpcAlertRuleActionResult: try: - install = SentryAppInstallation.objects.get(uuid=install_uuid) + install = SentryAppInstallation.objects.using_replica().get(uuid=install_uuid) except SentryAppInstallation.DoesNotExist: return RpcAlertRuleActionResult( success=False, From 465d0bbe836b812197c332116504729efdad0d5d Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Tue, 10 Jun 2025 15:15:37 -0700 Subject: [PATCH 06/10] removed the broken ones --- src/sentry/sentry_apps/services/app/impl.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index 0701b077915b80..d54619f5ced405 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -163,7 +163,7 @@ def get_custom_alert_rule_actions( def get_component_contexts( self, *, filter: SentryAppInstallationFilterArgs, component_type: str ) -> list[RpcSentryAppComponentContext]: - install_query = self._FQ.base_query().using_replica() + install_query = self._FQ.base_query() install_query = self._FQ.apply_filters(install_query, filter) install_query = install_query.select_related("sentry_app", "sentry_app__application") install_map: dict[int, list[SentryAppInstallation]] = defaultdict(list) @@ -192,7 +192,7 @@ def get_installation_component_contexts( component_type: str, include_contexts_without_component: bool = False, ) -> list[RpcSentryAppComponentContext]: - install_query = self._FQ.base_query().using_replica() + install_query = self._FQ.base_query() install_query = self._FQ.apply_filters(install_query, filter) app_ids = install_query.values_list("sentry_app_id", flat=True) @@ -263,13 +263,9 @@ def apply_filters( # Internal Integrations follow this pattern because they can have multiple tokens. # Decompose this query instead of using a subquery for performance. - install_token_list = ( - SentryAppInstallationToken.objects.using_replica() - .filter( - api_token_id=filters["api_installation_token_id"], - ) - .values_list("sentry_app_installation_id", flat=True) - ) + install_token_list = SentryAppInstallationToken.objects.filter( + api_token_id=filters["api_installation_token_id"], + ).values_list("sentry_app_installation_id", flat=True) query = query.filter( Q(api_token_id=filters["api_installation_token_id"]) @@ -301,15 +297,13 @@ def find_installation_by_proxy_user( return serialize_sentry_app_installation(installation, sentry_app) def get_installation_token(self, *, organization_id: int, provider: str) -> str | None: - return SentryAppInstallationToken.objects.using_replica().get_token( - organization_id, provider - ) + return SentryAppInstallationToken.objects.get_token(organization_id, provider) def trigger_sentry_app_action_creators( self, *, fields: list[Mapping[str, Any]], install_uuid: str | None ) -> RpcAlertRuleActionResult: try: - install = SentryAppInstallation.objects.using_replica().get(uuid=install_uuid) + install = SentryAppInstallation.objects.get(uuid=install_uuid) except SentryAppInstallation.DoesNotExist: return RpcAlertRuleActionResult( success=False, From c2597f877f2225f9df26d1bf7b338b8f5a4edf94 Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Wed, 11 Jun 2025 13:47:09 -0700 Subject: [PATCH 07/10] update some to get from cache --- src/sentry/sentry_apps/services/app/impl.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index d54619f5ced405..d46c9deb6b255e 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -61,12 +61,14 @@ def get_many( def find_app_components(self, *, app_id: int) -> list[RpcSentryAppComponent]: return [ serialize_sentry_app_component(c) - for c in SentryAppComponent.objects.using_replica().filter(sentry_app_id=app_id) + for c in SentryAppComponent.objects.get_from_cache() + .using_replica() + .filter(sentry_app_id=app_id) ] def get_sentry_app_by_id(self, *, id: int) -> RpcSentryApp | None: try: - sentry_app = SentryApp.objects.using_replica().get(id=id) + sentry_app = SentryApp.objects.get_from_cache().using_replica().get(id=id) except SentryApp.DoesNotExist: return None return serialize_sentry_app(sentry_app) From 950022700e68c59ca87ce1df748db0016d3fe63c Mon Sep 17 00:00:00 2001 From: Neo Huang <126607112+kneeyo1@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:04:29 -0700 Subject: [PATCH 08/10] Update src/sentry/sentry_apps/services/app/impl.py Co-authored-by: Mark Story --- src/sentry/sentry_apps/services/app/impl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index d46c9deb6b255e..22cc38e5ac47cb 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -68,7 +68,7 @@ def find_app_components(self, *, app_id: int) -> list[RpcSentryAppComponent]: def get_sentry_app_by_id(self, *, id: int) -> RpcSentryApp | None: try: - sentry_app = SentryApp.objects.get_from_cache().using_replica().get(id=id) + sentry_app = SentryApp.objects.get_from_cache(id=id, use_replica=True) except SentryApp.DoesNotExist: return None return serialize_sentry_app(sentry_app) From 2080dc2236dfc0c69db6ebde1c0a54a2e73e09b3 Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Thu, 12 Jun 2025 11:07:12 -0700 Subject: [PATCH 09/10] fix cache call --- src/sentry/sentry_apps/services/app/impl.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index 22cc38e5ac47cb..9c56f5d41894cc 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -61,9 +61,7 @@ def get_many( def find_app_components(self, *, app_id: int) -> list[RpcSentryAppComponent]: return [ serialize_sentry_app_component(c) - for c in SentryAppComponent.objects.get_from_cache() - .using_replica() - .filter(sentry_app_id=app_id) + for c in SentryAppComponent.objects.using_replica().filter(sentry_app_id=app_id) ] def get_sentry_app_by_id(self, *, id: int) -> RpcSentryApp | None: From 6ab800e2655c1ab29ee5d6acae41ac4bf001b1a0 Mon Sep 17 00:00:00 2001 From: kneeyo1 Date: Thu, 12 Jun 2025 16:20:44 -0700 Subject: [PATCH 10/10] lots of test cases dont expect the cache it looks like --- src/sentry/sentry_apps/services/app/impl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/sentry_apps/services/app/impl.py b/src/sentry/sentry_apps/services/app/impl.py index 9c56f5d41894cc..d54619f5ced405 100644 --- a/src/sentry/sentry_apps/services/app/impl.py +++ b/src/sentry/sentry_apps/services/app/impl.py @@ -66,7 +66,7 @@ def find_app_components(self, *, app_id: int) -> list[RpcSentryAppComponent]: def get_sentry_app_by_id(self, *, id: int) -> RpcSentryApp | None: try: - sentry_app = SentryApp.objects.get_from_cache(id=id, use_replica=True) + sentry_app = SentryApp.objects.using_replica().get(id=id) except SentryApp.DoesNotExist: return None return serialize_sentry_app(sentry_app)