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
1 change: 0 additions & 1 deletion src/sentry/backup/comparators.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,6 @@ def get_default_comparators() -> dict[str, list[JSONScrubbingComparator]]:
DateUpdatedComparator("date_updated"),
DateUpdatedComparator("date_added"),
],
"sentry.incident": [UUID4Comparator("detection_uuid")],
"sentry.integration": [DateUpdatedComparator("date_updated")],
"sentry.orgauthtoken": [
HashObfuscatingComparator("token_hashed", "token_last_characters")
Expand Down
1 change: 0 additions & 1 deletion src/sentry/deletions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ def load_defaults(manager: DeletionTaskManager) -> None:
manager.register(incidents.AlertRule, defaults.AlertRuleDeletionTask)
manager.register(incidents.AlertRuleTrigger, defaults.AlertRuleTriggerDeletionTask)
manager.register(incidents.AlertRuleTriggerAction, defaults.AlertRuleTriggerActionDeletionTask)
manager.register(incidents.Incident, defaults.IncidentDeletionTask)
manager.register(integrations.OrganizationIntegration, defaults.OrganizationIntegrationDeletionTask)
manager.register(integrations.RepositoryProjectPathConfig, defaults.RepositoryProjectPathConfigDeletionTask)
manager.register(investigations.Investigation, defaults.InvestigationDeletionTask)
Expand Down
1 change: 0 additions & 1 deletion src/sentry/deletions/defaults/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from .file import * # noqa: F401,F403
from .group import * # noqa: F401,F403
from .grouphash import * # noqa: F401,F403
from .incident import * # noqa: F401,F403
from .investigation import * # noqa: F401,F403
from .monitor import * # noqa: F401,F403
from .monitor_checkin import * # noqa: F401,F403
Expand Down
2 changes: 0 additions & 2 deletions src/sentry/deletions/defaults/alertrule.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ class AlertRuleDeletionTask(ModelDeletionTask[AlertRule]):

def get_child_relations(self, instance: AlertRule) -> list[BaseRelation]:
from sentry.incidents.models.alert_rule import AlertRuleTrigger
from sentry.incidents.models.incident import Incident
from sentry.workflow_engine.models import AlertRuleWorkflow

return [
ModelRelation(AlertRuleTrigger, {"alert_rule_id": instance.id}),
ModelRelation(Incident, {"alert_rule_id": instance.id}),
ModelRelation(
AlertRuleDetector,
{"alert_rule_id": instance.id},
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/deletions/defaults/detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def get_child_relations(self, instance: Detector) -> list[BaseRelation]:

# If this detector was dual-written from an AlertRule, cascade deletion
# to the AlertRule. AlertRuleDeletionTask will handle cleaning up
# AlertRuleDetector, AlertRuleWorkflow, triggers, and incidents.
# AlertRuleDetector, AlertRuleWorkflow, and triggers.
# NOTE: AlertRule must be deleted before DataSource so that
# QuerySubscriptionDeletionTask sees no remaining AlertRule referencing
# the SnubaQuery and can safely delete it.
Expand Down
8 changes: 0 additions & 8 deletions src/sentry/deletions/defaults/incident.py

This file was deleted.

2 changes: 0 additions & 2 deletions src/sentry/deletions/defaults/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ def get_child_relations(self, instance: Organization) -> list[BaseRelation]:
from sentry.deletions.defaults.discoversavedquery import DiscoverSavedQueryDeletionTask
from sentry.discover.models import DiscoverSavedQuery, TeamKeyTransaction
from sentry.incidents.models.alert_rule import AlertRule
from sentry.incidents.models.incident import Incident
from sentry.integrations.models.external_issue import ExternalIssue
from sentry.investigations.models import Investigation
from sentry.models.artifactbundle import ArtifactBundle
Expand All @@ -54,7 +53,6 @@ def get_child_relations(self, instance: Organization) -> list[BaseRelation]:
OrganizationMember,
Repository,
CommitAuthor,
Incident,
AlertRule,
Release,
Investigation,
Expand Down
7 changes: 0 additions & 7 deletions src/sentry/deletions/defaults/querysubscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@


class QuerySubscriptionDeletionTask(ModelDeletionTask[QuerySubscription]):
def delete_instance(self, instance: QuerySubscription) -> None:
from sentry.incidents.models.incident import Incident

# Clear the foreign key as the schema was created without a cascade clause
Incident.objects.filter(subscription_id=instance.id).update(subscription_id=None)
super().delete_instance(instance)

def get_child_relations(self, instance: QuerySubscription) -> list[BaseRelation]:
from sentry.incidents.models.alert_rule import AlertRule
from sentry.snuba.models import SnubaQuery
Expand Down
65 changes: 3 additions & 62 deletions src/sentry/incidents/models/incident.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,12 @@
from __future__ import annotations

import logging
from datetime import datetime, timedelta
from enum import Enum
from typing import Any, ClassVar
from uuid import uuid4

from django.db import IntegrityError, models, router, transaction
from django.db import models
from django.utils import timezone

from sentry.backup.dependencies import PrimaryKeyMap
from sentry.backup.helpers import ImportFlags
from sentry.backup.scopes import ImportScope, RelocationScope
from sentry.backup.scopes import RelocationScope
from sentry.db.models import FlexibleForeignKey, Model, UUIDField, cell_silo_model
from sentry.db.models.manager.base import BaseManager
from sentry.models.organization import Organization
from sentry.utils.retries import TimedRetryPolicy

logger = logging.getLogger(__name__)


class IncidentManager(BaseManager["Incident"]):
@TimedRetryPolicy.wrap(timeout=5, exceptions=(IntegrityError,))
def create(self, organization: Organization, **kwargs: Any) -> Incident:
"""
Creates an Incident. Fetches the maximum identifier value for the org
and increments it by one. If two incidents are created for the
Organization at the same time then an integrity error will be thrown,
and we'll retry again several times. I prefer to lock optimistically
here since if we're creating multiple Incidents a second for an
Organization then we're likely failing at making Incidents useful.
"""
with transaction.atomic(router.db_for_write(Organization)):
result = self.filter(organization=organization).aggregate(models.Max("identifier"))
identifier = result["identifier__max"]
if identifier is None:
identifier = 1
else:
identifier += 1

return super().create(organization=organization, identifier=identifier, **kwargs)


class IncidentType(Enum):
Expand Down Expand Up @@ -79,9 +46,7 @@ class Incident(Model):
- UI should be able to handle multiple active incidents
"""

__relocation_scope__ = RelocationScope.Global

objects: ClassVar[IncidentManager] = IncidentManager()
__relocation_scope__ = RelocationScope.Excluded

organization = FlexibleForeignKey(
"sentry.Organization", on_delete=models.DO_NOTHING, db_constraint=False
Expand Down Expand Up @@ -115,30 +80,6 @@ class Meta:
unique_together = (("organization", "identifier"),)
indexes = (models.Index(fields=("alert_rule", "type", "status")),)

@property
def current_end_date(self) -> datetime:
"""
Returns the current end of the incident. Either the date it was closed,
or the current time if it's still open.
"""
return self.date_closed if self.date_closed else timezone.now()

@property
def duration(self) -> timedelta:
return self.current_end_date - self.date_started

def normalize_before_relocation_import(
self, pk_map: PrimaryKeyMap, scope: ImportScope, flags: ImportFlags
) -> int | None:
old_pk = super().normalize_before_relocation_import(pk_map, scope, flags)
if old_pk is None:
return None

# Generate a new UUID, if one exists.
if self.detection_uuid:
self.detection_uuid = uuid4()
return old_pk


class IncidentActivityType(Enum):
"""Numeric activity types retained for legacy-compatible response payloads."""
Expand Down
41 changes: 0 additions & 41 deletions src/sentry/testutils/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,6 @@
AlertRuleTrigger,
AlertRuleTriggerAction,
)
from sentry.incidents.models.incident import (
Incident,
IncidentType,
)
from sentry.incidents.utils.constants import INCIDENTS_SNUBA_SUBSCRIPTION_TYPE
from sentry.integrations.models.data_forwarder import DataForwarder
from sentry.integrations.models.doc_integration import DocIntegration
Expand Down Expand Up @@ -2075,43 +2071,6 @@ def create_integration_external_project(
organization_integration_id=oi.id, *args, **kwargs
)

@staticmethod
@assume_test_silo_mode(SiloMode.CELL)
def create_incident(
organization,
projects,
detection_uuid=None,
status=1,
title=None,
query="test query",
date_started=None,
date_detected=None,
date_closed=None,
alert_rule=None,
subscription=None,
):
if not title:
title = petname.generate(2, " ", letters=10).title()
# Projects configure the default alert rule, not an incident-project relation.
if alert_rule is None:
alert_rule = Factories.create_alert_rule(
organization, projects, query=query, time_window=1
)

incident = Incident.objects.create(
organization=organization,
detection_uuid=detection_uuid,
status=status,
title=title,
alert_rule=alert_rule,
date_started=date_started or timezone.now(),
date_detected=date_detected or timezone.now(),
date_closed=timezone.now() if date_closed is not None else date_closed,
type=IncidentType.ALERT_TRIGGERED.value,
subscription=subscription,
)
return incident

@staticmethod
@assume_test_silo_mode(SiloMode.CELL)
def create_alert_rule(
Expand Down
8 changes: 0 additions & 8 deletions src/sentry/testutils/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,14 +573,6 @@ def create_integration_external_issue(self, *args, **kwargs):
def create_integration_external_project(self, *args, **kwargs):
return Factories.create_integration_external_project(*args, **kwargs)

def create_incident(self, organization=None, projects=None, *args, **kwargs):
if not organization:
organization = self.organization
if projects is None:
projects = [self.project]

return Factories.create_incident(organization, projects, *args, **kwargs)

def create_alert_rule(self, organization=None, projects=None, *args, **kwargs) -> AlertRule:
if not organization:
organization = self.organization
Expand Down
3 changes: 0 additions & 3 deletions src/sentry/testutils/helpers/backups.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,6 @@ def create_exhaustive_organization(
trigger = self.create_alert_rule_trigger(alert_rule=alert)
self.create_alert_rule_trigger_action(alert_rule_trigger=trigger)

# Incident*
self.create_incident(org, [project])

# Dashboard
dashboard = Dashboard.objects.create(
title=f"Dashboard 1 for {slug}",
Expand Down
28 changes: 4 additions & 24 deletions tests/sentry/deletions/test_alert_rule.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from unittest.mock import MagicMock, patch

import orjson
from django.utils import timezone
from urllib3 import HTTPResponse

from sentry.deletions.tasks.scheduled import run_scheduled_deletions
Expand All @@ -12,7 +11,6 @@
AlertRuleSensitivity,
AlertRuleTrigger,
)
from sentry.incidents.models.incident import Incident
from sentry.models.groupopenperiod import GroupOpenPeriod
from sentry.models.organization import Organization
from sentry.testutils.helpers.datetime import before_now
Expand All @@ -31,14 +29,6 @@ def test_simple(self) -> None:
organization = self.create_organization()
alert_rule = self.create_alert_rule(organization=organization)
alert_rule_trigger = self.create_alert_rule_trigger(alert_rule=alert_rule)
incident = self.create_incident(
organization,
title="Incident #1",
date_started=timezone.now(),
date_detected=timezone.now(),
projects=[self.project],
alert_rule=alert_rule,
)
one_minute = before_now(minutes=1).isoformat()
event = self.store_event(
data={"timestamp": one_minute, "fingerprint": ["group1"]}, project_id=self.project.id
Expand All @@ -47,8 +37,8 @@ def test_simple(self) -> None:
assert group
group_open_period = GroupOpenPeriod.objects.get(project=self.project, group=group)
self.create_incident_group_open_period(
incident_id=incident.id,
incident_identifier=incident.identifier,
incident_id=123,
incident_identifier=42,
group_open_period=group_open_period,
)

Expand All @@ -65,10 +55,9 @@ def test_simple(self) -> None:
assert Organization.objects.filter(id=organization.id).exists()
assert not AlertRule.objects.filter(id=alert_rule.id).exists()
assert not AlertRuleTrigger.objects.filter(id=alert_rule_trigger.id).exists()
assert not Incident.objects.filter(id=incident.id).exists()
assert IncidentGroupOpenPeriod.objects.filter(
incident_id=incident.id,
incident_identifier=incident.identifier,
incident_id=123,
incident_identifier=42,
group_open_period=group_open_period,
).exists()
assert GroupOpenPeriod.objects.filter(project=self.project, group=group).exists()
Expand All @@ -95,14 +84,6 @@ def test_dynamic_alert_rule(self, mock_store_request: MagicMock) -> None:
alert_rule_trigger = self.create_alert_rule_trigger(
alert_rule=alert_rule, alert_threshold=0
)
incident = self.create_incident(
organization,
title="Incident #1",
date_started=timezone.now(),
date_detected=timezone.now(),
projects=[self.project],
alert_rule=alert_rule,
)

self.ScheduledDeletion.schedule(instance=alert_rule, days=0)

Expand All @@ -112,4 +93,3 @@ def test_dynamic_alert_rule(self, mock_store_request: MagicMock) -> None:
assert Organization.objects.filter(id=organization.id).exists()
assert not AlertRule.objects.filter(id=alert_rule.id).exists()
assert not AlertRuleTrigger.objects.filter(id=alert_rule_trigger.id).exists()
assert not Incident.objects.filter(id=incident.id).exists()
50 changes: 0 additions & 50 deletions tests/sentry/deletions/test_incident.py

This file was deleted.

Loading
Loading