From b65b82187a1de8cee83cfbbbb67c59df21c8d722 Mon Sep 17 00:00:00 2001 From: Shashank Jarmale Date: Wed, 5 Nov 2025 12:02:02 -0800 Subject: [PATCH 1/2] Enable deletion from EAP by default, with a killswitch option --- src/sentry/deletions/tasks/nodestore.py | 3 +-- src/sentry/options/defaults.py | 10 ++++---- tests/sentry/eventstream/test_eap.py | 32 +++++++------------------ 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/sentry/deletions/tasks/nodestore.py b/src/sentry/deletions/tasks/nodestore.py index 2a79be32e7e7c3..cf8b1fb8de456f 100644 --- a/src/sentry/deletions/tasks/nodestore.py +++ b/src/sentry/deletions/tasks/nodestore.py @@ -215,8 +215,7 @@ def delete_events_from_eap( group_ids: Sequence[int], dataset: Dataset, ) -> None: - eap_deletion_allowlist = options.get("eventstream.eap.deletion_enabled.organization_allowlist") - if organization_id not in eap_deletion_allowlist: + if not options.get("eventstream.eap.deletion-enabled"): return try: diff --git a/src/sentry/options/defaults.py b/src/sentry/options/defaults.py index 25426d20894c4f..50f895a5913c78 100644 --- a/src/sentry/options/defaults.py +++ b/src/sentry/options/defaults.py @@ -3592,12 +3592,12 @@ flags=FLAG_ALLOW_EMPTY | FLAG_AUTOMATOR_MODIFIABLE, ) -# The allowlist of organization IDs for which deletion from EAP is enabled. +# Controls whether deletion from EAP is enabled. register( - "eventstream.eap.deletion_enabled.organization_allowlist", - type=Sequence, - default=[], - flags=FLAG_ALLOW_EMPTY | FLAG_AUTOMATOR_MODIFIABLE, + "eventstream.eap.deletion-enabled", + type=Bool, + default=True, + flags=FLAG_AUTOMATOR_MODIFIABLE, ) # Send logs for sentry app webhooks sent. Should only be enabled for debugging a specific app or installation. diff --git a/tests/sentry/eventstream/test_eap.py b/tests/sentry/eventstream/test_eap.py index f053c6849ca485..5f417139cd0610 100644 --- a/tests/sentry/eventstream/test_eap.py +++ b/tests/sentry/eventstream/test_eap.py @@ -23,13 +23,9 @@ def test_deletion_with_error_dataset(self, mock_rpc): matching_items_count=150, ) - with self.options( - {"eventstream.eap.deletion_enabled.organization_allowlist": [self.organization_id]} - ): - delete_events_from_eap( - self.organization_id, self.project_id, self.group_ids, Dataset.Events - ) - + delete_events_from_eap( + self.organization_id, self.project_id, self.group_ids, Dataset.Events + ) assert mock_rpc.call_count == 1 request = mock_rpc.call_args[0][0] @@ -50,29 +46,17 @@ def test_multiple_group_ids(self, mock_rpc): many_group_ids = [10, 20, 30, 40, 50] - with self.options( - {"eventstream.eap.deletion_enabled.organization_allowlist": [self.organization_id]} - ): - delete_events_from_eap( - self.organization_id, self.project_id, many_group_ids, Dataset.Events - ) + delete_events_from_eap( + self.organization_id, self.project_id, many_group_ids, Dataset.Events + ) request = mock_rpc.call_args[0][0] group_filter = request.filters[0].filter.and_filter.filters[1] assert list(group_filter.comparison_filter.value.val_int_array.values) == many_group_ids @patch("sentry.eventstream.eap.snuba_rpc.rpc") - def test_organization_not_in_allowlist_skips_deletion(self, mock_rpc): - with self.options({"eventstream.eap.deletion_enabled.organization_allowlist": [456, 789]}): - delete_events_from_eap( - self.organization_id, self.project_id, self.group_ids, Dataset.Events - ) - - mock_rpc.assert_not_called() - - @patch("sentry.eventstream.eap.snuba_rpc.rpc") - def test_empty_allowlist_skips_deletion(self, mock_rpc): - with self.options({"eventstream.eap.deletion_enabled.organization_allowlist": []}): + def test_eap_deletion_disabled_skips_deletion(self, mock_rpc): + with self.options({"eventstream.eap.deletion-enabled": False}): delete_events_from_eap( self.organization_id, self.project_id, self.group_ids, Dataset.Events ) From b7e8de6f71bb34ebb1ee3cd828636cc168744781 Mon Sep 17 00:00:00 2001 From: Shashank Jarmale Date: Tue, 18 Nov 2025 14:45:25 -0800 Subject: [PATCH 2/2] Update log messages & recorded metrics in EAP deletion flow --- src/sentry/deletions/tasks/nodestore.py | 22 +++++++++------------- tests/sentry/eventstream/test_eap.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/sentry/deletions/tasks/nodestore.py b/src/sentry/deletions/tasks/nodestore.py index cf8b1fb8de456f..4290941b597deb 100644 --- a/src/sentry/deletions/tasks/nodestore.py +++ b/src/sentry/deletions/tasks/nodestore.py @@ -219,33 +219,29 @@ def delete_events_from_eap( return try: - response = delete_groups_from_eap_rpc( + delete_groups_from_eap_rpc( organization_id=organization_id, project_id=project_id, group_ids=group_ids, referrer="deletions.group.eap", ) - logger.info( - "eap.delete_groups.completed", - extra={ - "organization_id": organization_id, - "project_id": project_id, - "group_count": len(group_ids), - "matching_items_count": response.matching_items_count, - }, + metrics.incr( + "deletions.group.eap.success", + tags={"dataset": dataset.value}, + sample_rate=1.0, ) - except Exception as e: + except Exception: logger.exception( - "eap.delete_groups.failed", + "Failed to delete groups from EAP", extra={ "organization_id": organization_id, "project_id": project_id, "group_ids": group_ids[:10], - "error": str(e), + "dataset": dataset.value, }, ) metrics.incr( - "deletions.eap.failed", + "deletions.group.eap.failure", tags={"dataset": dataset.value}, sample_rate=1.0, ) diff --git a/tests/sentry/eventstream/test_eap.py b/tests/sentry/eventstream/test_eap.py index 5f417139cd0610..1ea42c09d74466 100644 --- a/tests/sentry/eventstream/test_eap.py +++ b/tests/sentry/eventstream/test_eap.py @@ -70,3 +70,15 @@ def test_empty_group_ids_raises_error(self): project_id=self.project_id, group_ids=[], ) + + @patch("sentry.eventstream.eap.snuba_rpc.rpc") + def test_exception_does_not_propagate(self, mock_rpc): + mock_rpc.side_effect = Exception("RPC connection failed") + + # Should not raise - exception should be caught + try: + delete_events_from_eap( + self.organization_id, self.project_id, self.group_ids, Dataset.Events + ) + except Exception: + pytest.fail("Exception should have been caught and not propagated")