From d19858d89bec2ccaf438e89ad6b38962b58492ec Mon Sep 17 00:00:00 2001 From: Christinarlong Date: Wed, 25 Jun 2025 16:26:37 -0700 Subject: [PATCH 1/3] add lufecycle for updating servicehooks --- src/sentry/sentry_apps/tasks/sentry_apps.py | 24 +++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sentry/sentry_apps/tasks/sentry_apps.py b/src/sentry/sentry_apps/tasks/sentry_apps.py index 01e5c772b71eca..47ce6a8925c361 100644 --- a/src/sentry/sentry_apps/tasks/sentry_apps.py +++ b/src/sentry/sentry_apps/tasks/sentry_apps.py @@ -786,10 +786,22 @@ def send_webhooks(installation: RpcSentryAppInstallation, event: str, **kwargs: def create_or_update_service_hooks_for_sentry_app( sentry_app_id: int, webhook_url: str, events: list[str], **kwargs: dict ) -> None: - installations = SentryAppInstallation.objects.filter(sentry_app_id=sentry_app_id) - for installation in installations: - create_or_update_service_hooks_for_installation( - installation=installation, - events=events, - webhook_url=webhook_url, + with SentryAppInteractionEvent( + operation_type=SentryAppInteractionType.MANAGEMENT, + event_type=SentryAppEventType.WEBHOOK_UPDATE, + ).capture() as lifecycle: + installations = SentryAppInstallation.objects.filter(sentry_app_id=sentry_app_id) + lifecycle.add_extras( + { + "installations": installations.values_list("id", flat=True), + "sentry_app_id": sentry_app_id, + "events": events, + } ) + + for installation in installations: + create_or_update_service_hooks_for_installation( + installation=installation, + events=events, + webhook_url=webhook_url, + ) From 9115edd106f7c4b7377e6c815bf12278eb16e1c8 Mon Sep 17 00:00:00 2001 From: Christinarlong Date: Thu, 26 Jun 2025 13:53:13 -0700 Subject: [PATCH 2/3] add test for slos --- .../sentry/sentry_apps/test_sentry_app_updater.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/sentry/sentry_apps/test_sentry_app_updater.py b/tests/sentry/sentry_apps/test_sentry_app_updater.py index b1d08808c6f72a..be5656b043b60e 100644 --- a/tests/sentry/sentry_apps/test_sentry_app_updater.py +++ b/tests/sentry/sentry_apps/test_sentry_app_updater.py @@ -213,7 +213,8 @@ def test_doesnt_update_status_if_not_superuser(self): self.updater.run(self.user) assert self.sentry_app.status == SentryAppStatus.UNPUBLISHED - def test_create_service_hook_on_update(self): + @patch("sentry.integrations.utils.metrics.EventLifecycle.record_event") + def test_create_service_hook_on_update(self, mock_record): self.create_project(organization=self.org) internal_app = self.create_internal_integration( name="Internal", organization=self.org, webhook_url=None, scopes=("event:read",) @@ -229,6 +230,17 @@ def test_create_service_hook_on_update(self): assert service_hook.url == "https://sentry.io/hook" assert service_hook.events == expand_events(["issue"]) + # SLO assertions + assert_success_metric(mock_record=mock_record) + + # APP_CREATE (success) -> WEBHOOK_UPDATE (success) + assert_count_of_metric( + mock_record=mock_record, outcome=EventLifecycleOutcome.STARTED, outcome_count=2 + ) + assert_count_of_metric( + mock_record=mock_record, outcome=EventLifecycleOutcome.SUCCESS, outcome_count=2 + ) + def test_delete_service_hook_on_update(self): self.create_project(organization=self.org) internal_app = self.create_internal_integration( From 2d9c0e834558b480e6567d9ad87eb36664b965db Mon Sep 17 00:00:00 2001 From: Christinarlong Date: Mon, 30 Jun 2025 13:45:35 -0700 Subject: [PATCH 3/3] remove installations list --- src/sentry/sentry_apps/tasks/sentry_apps.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/sentry/sentry_apps/tasks/sentry_apps.py b/src/sentry/sentry_apps/tasks/sentry_apps.py index 47ce6a8925c361..2160b0acd12f99 100644 --- a/src/sentry/sentry_apps/tasks/sentry_apps.py +++ b/src/sentry/sentry_apps/tasks/sentry_apps.py @@ -790,14 +790,8 @@ def create_or_update_service_hooks_for_sentry_app( operation_type=SentryAppInteractionType.MANAGEMENT, event_type=SentryAppEventType.WEBHOOK_UPDATE, ).capture() as lifecycle: + lifecycle.add_extras({"sentry_app_id": sentry_app_id, "events": events}) installations = SentryAppInstallation.objects.filter(sentry_app_id=sentry_app_id) - lifecycle.add_extras( - { - "installations": installations.values_list("id", flat=True), - "sentry_app_id": sentry_app_id, - "events": events, - } - ) for installation in installations: create_or_update_service_hooks_for_installation(