From 567a86dcbe10fe9740d01beb9abbacd7c01aa4d8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 5 Sep 2025 21:12:10 +0000 Subject: [PATCH] Refactor Seer API calls to use signed requests Co-authored-by: jenn --- .../seer/similarity/grouping_records.py | 17 +++-- .../seer/similarity/test_grouping_records.py | 66 ++++++++++++++++++- 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/sentry/seer/similarity/grouping_records.py b/src/sentry/seer/similarity/grouping_records.py index a1dbf187581ded..dabd08ff21ef84 100644 --- a/src/sentry/seer/similarity/grouping_records.py +++ b/src/sentry/seer/similarity/grouping_records.py @@ -89,11 +89,11 @@ def call_seer_to_delete_project_grouping_records( project_id: int, ) -> bool: try: - # TODO: Move this over to POST json_api implementation - response = seer_grouping_connection_pool.urlopen( - "GET", - f"{SEER_PROJECT_GROUPING_RECORDS_DELETE_URL}/{project_id}", - headers={"Content-Type": "application/json;charset=utf-8"}, + body = {"project_id": project_id} + response = make_signed_seer_api_request( + seer_grouping_connection_pool, + SEER_PROJECT_GROUPING_RECORDS_DELETE_URL, + body=json.dumps(body).encode("utf-8"), timeout=POST_BULK_GROUPING_RECORDS_TIMEOUT, ) except ReadTimeoutError: @@ -130,11 +130,10 @@ def call_seer_to_delete_these_hashes(project_id: int, hashes: Sequence[str]) -> extra = {"project_id": project_id, "hashes": hashes} try: body = {"project_id": project_id, "hash_list": hashes} - response = seer_grouping_connection_pool.urlopen( - "POST", + response = make_signed_seer_api_request( + seer_grouping_connection_pool, SEER_HASH_GROUPING_RECORDS_DELETE_URL, - body=json.dumps(body), - headers={"Content-Type": "application/json;charset=utf-8"}, + body=json.dumps(body).encode("utf-8"), timeout=POST_BULK_GROUPING_RECORDS_TIMEOUT, ) except ReadTimeoutError: diff --git a/tests/sentry/seer/similarity/test_grouping_records.py b/tests/sentry/seer/similarity/test_grouping_records.py index 7a3321a209ff60..0e42503f94ba3f 100644 --- a/tests/sentry/seer/similarity/test_grouping_records.py +++ b/tests/sentry/seer/similarity/test_grouping_records.py @@ -11,6 +11,7 @@ from sentry.seer.similarity.grouping_records import ( POST_BULK_GROUPING_RECORDS_TIMEOUT, CreateGroupingRecordsRequest, + call_seer_to_delete_project_grouping_records, call_seer_to_delete_these_hashes, post_bulk_grouping_records, ) @@ -175,7 +176,7 @@ def test_post_bulk_grouping_records_use_reranking( @django_db_all @mock.patch("sentry.seer.similarity.grouping_records.logger") -@mock.patch("sentry.seer.similarity.grouping_records.seer_grouping_connection_pool.urlopen") +@mock.patch("sentry.seer.similarity.grouping_records.make_signed_seer_api_request") def test_delete_grouping_records_by_hash_success( mock_seer_request: MagicMock, mock_logger: MagicMock ): @@ -197,7 +198,7 @@ def test_delete_grouping_records_by_hash_success( @django_db_all @mock.patch("sentry.seer.similarity.grouping_records.logger") -@mock.patch("sentry.seer.similarity.grouping_records.seer_grouping_connection_pool.urlopen") +@mock.patch("sentry.seer.similarity.grouping_records.make_signed_seer_api_request") def test_delete_grouping_records_by_hash_timeout( mock_seer_request: MagicMock, mock_logger: MagicMock ): @@ -220,7 +221,7 @@ def test_delete_grouping_records_by_hash_timeout( @django_db_all @mock.patch("sentry.seer.similarity.grouping_records.logger") -@mock.patch("sentry.seer.similarity.grouping_records.seer_grouping_connection_pool.urlopen") +@mock.patch("sentry.seer.similarity.grouping_records.make_signed_seer_api_request") def test_delete_grouping_records_by_hash_failure( mock_seer_request: MagicMock, mock_logger: MagicMock ): @@ -239,3 +240,62 @@ def test_delete_grouping_records_by_hash_failure( "project_id": project_id, }, ) + + +@django_db_all +@mock.patch("sentry.seer.similarity.grouping_records.logger") +@mock.patch("sentry.seer.similarity.grouping_records.make_signed_seer_api_request") +def test_delete_project_grouping_records_success( + mock_seer_request: MagicMock, mock_logger: MagicMock +): + mock_seer_request.return_value = HTTPResponse( + json.dumps({"success": True}).encode("utf-8"), status=200 + ) + + project_id = 1 + response = call_seer_to_delete_project_grouping_records(project_id) + assert response is True + mock_logger.info.assert_called_with( + "seer.delete_grouping_records.project.success", + extra={"project_id": project_id}, + ) + + +@django_db_all +@mock.patch("sentry.seer.similarity.grouping_records.logger") +@mock.patch("sentry.seer.similarity.grouping_records.make_signed_seer_api_request") +def test_delete_project_grouping_records_timeout( + mock_seer_request: MagicMock, mock_logger: MagicMock +): + mock_seer_request.side_effect = ReadTimeoutError( + DUMMY_POOL, "/v0/issues/similar-issues/grouping-record/delete", "read timed out" + ) + project_id = 1 + response = call_seer_to_delete_project_grouping_records(project_id) + assert response is False + mock_logger.exception.assert_called_with( + "seer.delete_grouping_records.project.timeout", + extra={ + "reason": "ReadTimeoutError", + "timeout": POST_BULK_GROUPING_RECORDS_TIMEOUT, + }, + ) + + +@django_db_all +@mock.patch("sentry.seer.similarity.grouping_records.logger") +@mock.patch("sentry.seer.similarity.grouping_records.make_signed_seer_api_request") +def test_delete_project_grouping_records_failure( + mock_seer_request: MagicMock, mock_logger: MagicMock +): + mock_seer_request.return_value = HTTPResponse( + b"\n\n500 Internal Server Error\n

Internal Server Error

\n

The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

\n", + reason="INTERNAL SERVER ERROR", + status=500, + ) + project_id = 1 + response = call_seer_to_delete_project_grouping_records(project_id) + assert response is False + mock_logger.error.assert_called_with( + "seer.delete_grouping_records.project.failure", + )