Skip to content
Open
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
46 changes: 38 additions & 8 deletions src/sentry/tasks/auto_ongoing_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
from datetime import datetime, timedelta, timezone

import sentry_sdk
from django.db.models import Max
from django.db.models import Max, OuterRef, Subquery

from sentry.issues.ongoing import TRANSITION_AFTER_DAYS, bulk_transition_group_to_ongoing
from sentry.models.group import Group, GroupStatus
from sentry.models.grouphistory import GroupHistoryStatus
from sentry.models.grouphistory import GroupHistory, GroupHistoryStatus
from sentry.silo.base import SiloMode
from sentry.tasks.base import instrumented_task
from sentry.taskworker.namespaces import issues_tasks
Expand Down Expand Up @@ -163,14 +163,28 @@ def get_total_count(results):
nonlocal total_count
total_count += len(results)

date_threshold = datetime.fromtimestamp(date_added_lte, timezone.utc)

# Use a subquery to get the most recent REGRESSED history date for each group.
# This ensures we only transition groups whose MOST RECENT regressed history
# is older than the threshold, not just any regressed history.
latest_regressed_subquery = (
GroupHistory.objects.filter(group_id=OuterRef("id"), status=GroupHistoryStatus.REGRESSED)
.values("group_id")
.annotate(max_date=Max("date_added"))
.values("max_date")[:1]
)

base_queryset = (
Group.objects.filter(
status=GroupStatus.UNRESOLVED,
substatus=GroupSubStatus.REGRESSED,
grouphistory__status=GroupHistoryStatus.REGRESSED,
)
.annotate(recent_regressed_history=Max("grouphistory__date_added"))
.filter(recent_regressed_history__lte=datetime.fromtimestamp(date_added_lte, timezone.utc))
.annotate(recent_regressed_history=Subquery(latest_regressed_subquery))
.filter(
recent_regressed_history__lte=date_threshold,
recent_regressed_history__isnull=False,
)
)

with sentry_sdk.start_span(name="iterate_chunked_group_ids"):
Expand Down Expand Up @@ -244,14 +258,30 @@ def get_total_count(results):
nonlocal total_count
total_count += len(results)

from django.db.models import Max, OuterRef, Subquery

date_threshold = datetime.fromtimestamp(date_added_lte, timezone.utc)

# Use a subquery to get the most recent ESCALATING history date for each group.
# This ensures we only transition groups whose MOST RECENT escalating history
# is older than the threshold, not just any escalating history.
latest_escalating_subquery = (
GroupHistory.objects.filter(group_id=OuterRef("id"), status=GroupHistoryStatus.ESCALATING)
.values("group_id")
.annotate(max_date=Max("date_added"))
.values("max_date")[:1]
)

base_queryset = (
Group.objects.filter(
status=GroupStatus.UNRESOLVED,
substatus=GroupSubStatus.ESCALATING,
grouphistory__status=GroupHistoryStatus.ESCALATING,
)
.annotate(recent_escalating_history=Max("grouphistory__date_added"))
.filter(recent_escalating_history__lte=datetime.fromtimestamp(date_added_lte, timezone.utc))
.annotate(recent_escalating_history=Subquery(latest_escalating_subquery))
.filter(
recent_escalating_history__lte=date_threshold,
recent_escalating_history__isnull=False,
)
)

with sentry_sdk.start_span(name="iterate_chunked_group_ids"):
Expand Down
67 changes: 67 additions & 0 deletions tests/sentry/tasks/test_auto_ongoing_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,73 @@ def test_not_all_groups_get_updated(self, mock_metrics_incr) -> None:
tags={"count": 0},
)

@freeze_time("2023-07-12 18:40:00Z")
def test_only_checks_most_recent_regressed_history(self) -> None:
"""
Test that only the MOST RECENT regressed history is checked against the threshold,
not just any regressed history.

Scenario:
- Group regressed 14 days ago (older than 7-day threshold)
- Group resolved 10 days ago
- Group regressed again 2 days ago (newer than 7-day threshold)

Expected: Group should NOT be transitioned because most recent regression is only 2 days old
"""
now = datetime.now(tz=timezone.utc)
project = self.create_project()
group = self.create_group(
project=project,
status=GroupStatus.UNRESOLVED,
substatus=GroupSubStatus.REGRESSED,
first_seen=now - timedelta(days=14),
)

# Create OLD regressed history (14 days ago) - this is OLDER than threshold
old_regressed_history = record_group_history(
group, GroupHistoryStatus.REGRESSED, actor=None, release=None
)
old_regressed_history.date_added = now - timedelta(days=14)
old_regressed_history.save(update_fields=["date_added"])

# Create resolved history in between (10 days ago)
resolved_history = record_group_history(
group, GroupHistoryStatus.RESOLVED, actor=None, release=None
)
resolved_history.date_added = now - timedelta(days=10)
resolved_history.save(update_fields=["date_added"])

# Create NEW regressed history (2 days ago) - this is NEWER than threshold
# This is the MOST RECENT regressed history
new_regressed_history = record_group_history(
group, GroupHistoryStatus.REGRESSED, actor=None, release=None
)
new_regressed_history.date_added = now - timedelta(days=2)
new_regressed_history.save(update_fields=["date_added"])

# Also create a recent group inbox entry
group_inbox = add_group_to_inbox(group, GroupInboxReason.REGRESSION)
group_inbox.date_added = now - timedelta(days=2)
group_inbox.save(update_fields=["date_added"])

with self.tasks():
schedule_auto_transition_to_ongoing()

# Group should NOT be transitioned because most recent regression is only 2 days old
group.refresh_from_db()
assert group.status == GroupStatus.UNRESOLVED
assert group.substatus == GroupSubStatus.REGRESSED # Should still be REGRESSED

# Should NOT have created an auto-ongoing activity
assert not Activity.objects.filter(
group=group, type=ActivityType.AUTO_SET_ONGOING.value
).exists()

# Should NOT have created an ONGOING history entry
assert not GroupHistory.objects.filter(
group=group, status=GroupHistoryStatus.ONGOING
).exists()


class ScheduleAutoEscalatingOngoingIssuesTest(TestCase):
@freeze_time("2023-07-12 18:40:00Z")
Expand Down
Loading