Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/sentry/tasks/llm_issue_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import logging

import sentry_sdk
from django.conf import settings
from pydantic import BaseModel

Expand Down Expand Up @@ -168,5 +169,6 @@ def detect_llm_issues_for_project(project_id: int) -> None:
),
},
)
except LLMIssueDetectionError:
continue # if one transaction encounters an error, don't block processing of the others
except LLMIssueDetectionError as e:
sentry_sdk.capture_exception(e)
continue
77 changes: 51 additions & 26 deletions tests/sentry/tasks/test_llm_issue_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pydantic import ValidationError as PydanticValidationError
from urllib3 import BaseHTTPResponse

from sentry.seer.sentry_data_models import Span, TraceData, Transaction
from sentry.tasks.llm_issue_detection import (
IssueDetectionResponse,
detect_llm_issues_for_project,
Expand Down Expand Up @@ -129,42 +130,59 @@ def test_detect_llm_issues_no_traces(self, mock_seer_api):

mock_seer_api.assert_not_called()

@patch("sentry.tasks.llm_issue_detection.get_trace_for_transaction")
@patch("sentry.tasks.llm_issue_detection.get_transactions_for_project")
@patch("sentry.tasks.llm_issue_detection.sentry_sdk.capture_exception")
@patch("sentry.tasks.llm_issue_detection.logger")
def test_detect_llm_issues_multiple_transactions_partial_errors(
self, mock_logger, mock_seer_api
self,
mock_logger,
mock_capture_exception,
mock_get_transactions,
mock_get_trace,
mock_seer_api,
):
"""Test that errors in some transactions don't block processing of others."""
transaction1_name = "transaction_1"
trace_id_1 = uuid.uuid4().hex
spans1 = [
self.create_span(
{
"description": "span-1",
"sentry_tags": {"transaction": transaction1_name},
"trace_id": trace_id_1,
"parent_span_id": None,
"is_segment": True,
},
start_ts=self.ten_mins_ago,
)
]

transaction2_name = "transaction_2"
trace_id_2 = uuid.uuid4().hex
spans2 = [
self.create_span(
{
"description": "span-2",
"sentry_tags": {"transaction": transaction2_name},
"trace_id": trace_id_2,
"parent_span_id": None,
"is_segment": True,
},
start_ts=self.ten_mins_ago,
)

mock_get_transactions.return_value = [
Transaction(name=transaction1_name, project_id=self.project.id),
Transaction(name=transaction2_name, project_id=self.project.id),
]

self.store_spans(spans1 + spans2, is_eap=True)
mock_get_trace.side_effect = [
TraceData(
trace_id=trace_id_1,
project_id=self.project.id,
transaction_name=transaction1_name,
total_spans=1,
spans=[
Span(
span_id="span1",
parent_span_id=None,
span_op="http",
span_description="test",
)
],
),
TraceData(
trace_id=trace_id_2,
project_id=self.project.id,
transaction_name=transaction2_name,
total_spans=1,
spans=[
Span(
span_id="span2",
parent_span_id=None,
span_op="http",
span_description="test",
)
],
),
]

error_response = Mock(spec=BaseHTTPResponse)
error_response.status = 500
Expand All @@ -189,6 +207,13 @@ def test_detect_llm_issues_multiple_transactions_partial_errors(
detect_llm_issues_for_project(self.project.id)

assert mock_seer_api.call_count == 2
assert mock_capture_exception.call_count == 1

captured_exception = mock_capture_exception.call_args[0][0]
assert captured_exception.project_id == self.project.id
assert captured_exception.trace_id == trace_id_1
assert captured_exception.status == 500

success_log_calls = [
call
for call in mock_logger.info.call_args_list
Expand Down
Loading