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
11 changes: 9 additions & 2 deletions src/sentry/deletions/defaults/monitor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from sentry.deletions.base import BaseRelation, ModelDeletionTask, ModelRelation
from sentry.deletions.base import (
BaseRelation,
BulkModelDeletionTask,
ModelDeletionTask,
ModelRelation,
)
from sentry.monitors.models import Monitor


Expand All @@ -7,6 +12,8 @@ def get_child_relations(self, instance: Monitor) -> list[BaseRelation]:
from sentry.monitors import models

return [
ModelRelation(models.MonitorCheckIn, {"monitor_id": instance.id}, ModelDeletionTask),
ModelRelation(
models.MonitorCheckIn, {"monitor_id": instance.id}, BulkModelDeletionTask
),
Comment on lines +15 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: MonitorCheckIn deletion via BulkModelDeletionTask will fail due to unhandled MonitorIncident foreign key references.
Severity: CRITICAL | Confidence: 0.95

🔍 Detailed Analysis

When MonitorCheckIn records are deleted using BulkModelDeletionTask, and MonitorIncident records still reference them via starting_checkin or resolving_checkin foreign keys, the database will attempt to enforce foreign key constraints. Since these foreign keys lack database-level CASCADE delete configuration, this will lead to database constraint violation errors and unexpected deletion failures, preventing the bulk delete operation from completing successfully. The PR author overlooked the existing MonitorIncident foreign key relationships to MonitorCheckIn.

💡 Suggested Fix

Create a MonitorIncidentDeletionTask to handle MonitorIncident deletion before MonitorCheckIn, or configure database-level CASCADE delete on the foreign keys, or revert to ModelDeletionTask for MonitorCheckIn to process child relations.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: src/sentry/deletions/defaults/monitor.py#L15-L17

Potential issue: When `MonitorCheckIn` records are deleted using
`BulkModelDeletionTask`, and `MonitorIncident` records still reference them via
`starting_checkin` or `resolving_checkin` foreign keys, the database will attempt to
enforce foreign key constraints. Since these foreign keys lack database-level `CASCADE`
delete configuration, this will lead to database constraint violation errors and
unexpected deletion failures, preventing the bulk delete operation from completing
successfully. The PR author overlooked the existing `MonitorIncident` foreign key
relationships to `MonitorCheckIn`.

Did we get this right? 👍 / 👎 to inform future reviews.

Reference_id: 2749526

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was conflicted about this, we have foreign keys with CASCADE set up on these. I believe this means they should be getting deleted automatically when the bulk task deletes them at the DB level, cursor agrees, I believe this is probably wrong but I am not sure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can always deploy and see if there are more optimizations.

ModelRelation(models.MonitorEnvironment, {"monitor_id": instance.id}),
]
9 changes: 7 additions & 2 deletions src/sentry/deletions/defaults/monitor_environment.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from sentry.deletions.base import BaseRelation, ModelDeletionTask, ModelRelation
from sentry.deletions.base import (
BaseRelation,
BulkModelDeletionTask,
ModelDeletionTask,
ModelRelation,
)
from sentry.monitors.models import MonitorEnvironment


Expand All @@ -10,6 +15,6 @@ def get_child_relations(self, instance: MonitorEnvironment) -> list[BaseRelation
ModelRelation(
models.MonitorCheckIn,
{"monitor_environment_id": instance.id},
ModelDeletionTask,
BulkModelDeletionTask,
),
]
Loading