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
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ pnpm-lock.yaml @getsentry/owners-js-de
/src/sentry/tasks/post_process.py @getsentry/issue-detection-backend
/src/sentry/tasks/unmerge.py @getsentry/issue-detection-backend
/src/sentry/tasks/weekly_escalating_forecast.py @getsentry/issue-detection-backend
/src/sentry/tasks/llm_issue_detection.py @getsentry/issue-detection-backend
/static/app/components/events/contexts/ @getsentry/issue-workflow
/static/app/components/events/eventTags/ @getsentry/issue-workflow
/static/app/components/events/highlights/ @getsentry/issue-workflow
Expand Down Expand Up @@ -615,6 +616,7 @@ pnpm-lock.yaml @getsentry/owners-js-de
/tests/sentry/tasks/test_merge.py @getsentry/issue-detection-backend
/tests/sentry/tasks/test_post_process.py @getsentry/issue-detection-backend
/tests/sentry/tasks/test_weekly_escalating_forecast.py @getsentry/issue-detection-backend
/tests/sentry/tasks/test_llm_issue_detection.py @getsentry/issue-detection-backend
/tests/snuba/search/ @getsentry/issue-workflow
## End of Issues

Expand Down
5 changes: 5 additions & 0 deletions src/sentry/conf/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,7 @@ def SOCIAL_AUTH_DEFAULT_USERNAME() -> str:
"sentry.tasks.email",
"sentry.tasks.embeddings_grouping.backfill_seer_grouping_records_for_project",
"sentry.tasks.groupowner",
"sentry.tasks.llm_issue_detection",
"sentry.tasks.merge",
"sentry.tasks.on_demand_metrics",
"sentry.tasks.options",
Expand Down Expand Up @@ -1102,6 +1103,10 @@ def SOCIAL_AUTH_DEFAULT_USERNAME() -> str:
"task": "ai_agent_monitoring:sentry.tasks.ai_agent_monitoring.fetch_ai_model_costs",
"schedule": task_crontab("*/30", "*", "*", "*", "*"),
},
"llm-issue-detection": {
"task": "issues:sentry.tasks.llm_issue_detection.run_llm_issue_detection",
"schedule": task_crontab("*/30", "*", "*", "*", "*"),
},
"preprod-detect-expired-artifacts": {
"task": "preprod:sentry.preprod.tasks.detect_expired_preprod_artifacts",
"schedule": task_crontab("0", "*", "*", "*", "*"),
Expand Down
57 changes: 57 additions & 0 deletions src/sentry/tasks/llm_issue_detection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from __future__ import annotations

import logging

from sentry import options
from sentry.models.project import Project
from sentry.tasks.base import instrumented_task
from sentry.taskworker.namespaces import issues_tasks

logger = logging.getLogger("sentry.tasks.llm_issue_detection")


def get_enabled_project_ids() -> list[int]:
"""
Get the list of project IDs that are explicitly enabled for LLM detection.

Returns the allowlist from system options.
"""
return options.get("issue-detection.llm-detection.projects-allowlist")


@instrumented_task(
name="sentry.tasks.llm_issue_detection.run_llm_issue_detection",
namespace=issues_tasks,
processing_deadline_duration=120,
)
def run_llm_issue_detection() -> None:
"""
Main scheduled task for LLM issue detection.
"""
if not options.get("issue-detection.llm-detection.enabled"):
return

enabled_project_ids = get_enabled_project_ids()
if not enabled_project_ids:
return

# Spawn a sub-task for each project
for project_id in enabled_project_ids:
detect_llm_issues_for_project.delay(project_id)


@instrumented_task(
name="sentry.tasks.llm_issue_detection.detect_llm_issues_for_project",
namespace=issues_tasks,
processing_deadline_duration=120,
)
def detect_llm_issues_for_project(project_id: int) -> None:
"""
Process a single project for LLM issue detection.
"""
project = Project.objects.get(id=project_id)

logger.info(
"Processing project for LLM detection",
extra={"project_id": project.id, "org_id": project.organization_id},
)
22 changes: 22 additions & 0 deletions tests/sentry/tasks/test_llm_issue_detection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from unittest.mock import patch

from sentry.tasks.llm_issue_detection import run_llm_issue_detection
from sentry.testutils.cases import TestCase


class LLMIssueDetectionTest(TestCase):
@patch("sentry.tasks.llm_issue_detection.detect_llm_issues_for_project.delay")
def test_run_detection_dispatches_sub_tasks(self, mock_delay):
"""Test run_detection spawns sub-tasks for each project."""
project = self.create_project()

with self.options(
{
"issue-detection.llm-detection.enabled": True,
"issue-detection.llm-detection.projects-allowlist": [project.id],
}
):
run_llm_issue_detection()

assert mock_delay.called
assert mock_delay.call_args[0][0] == project.id
Loading