44from collections .abc import Collection , Mapping
55from typing import TYPE_CHECKING , Any , ClassVar , overload
66
7- from django .db import models
7+ from django .db import models , router , transaction
88from django .utils import timezone
99from jsonschema import ValidationError
1010
1616from sentry .db .models .fields .hybrid_cloud_foreign_key import HybridCloudForeignKey
1717from sentry .db .models .manager .base_query_set import BaseQuerySet
1818from sentry .db .models .paranoia import ParanoidManager , ParanoidModel
19- from sentry .hybridcloud .models .outbox import ControlOutboxBase , outbox_context
19+ from sentry .hybridcloud .models .outbox import ControlOutbox , ControlOutboxBase , outbox_context
2020from sentry .hybridcloud .outbox .base import ReplicatedControlModel
21- from sentry .hybridcloud .outbox .category import OutboxCategory
21+ from sentry .hybridcloud .outbox .category import OutboxCategory , OutboxScope
2222from sentry .projects .services .project import RpcProject
2323from sentry .sentry_apps .services .app .model import RpcSentryAppComponent , RpcSentryAppInstallation
2424from sentry .sentry_apps .utils .errors import (
2525 SentryAppError ,
2626 SentryAppIntegratorError ,
2727 SentryAppSentryError ,
2828)
29- from sentry .types .region import find_regions_for_orgs
29+ from sentry .types .region import find_all_region_names , find_regions_for_orgs
3030
3131if TYPE_CHECKING :
3232 from sentry .models .project import Project
@@ -124,6 +124,12 @@ def save(self, *args, **kwargs):
124124 self .date_updated = timezone .now ()
125125 return super ().save (* args , ** kwargs )
126126
127+ def delete (self , * args , ** kwargs ):
128+ with outbox_context (transaction .atomic (using = router .db_for_write (SentryAppInstallation ))):
129+ for outbox in self .outboxes_for_delete ():
130+ outbox .save ()
131+ return super ().delete (* args , ** kwargs )
132+
127133 @property
128134 def api_application_id (self ) -> int | None :
129135 from sentry .sentry_apps .models .sentry_app import SentryApp
@@ -141,6 +147,19 @@ def outboxes_for_update(self, shard_identifier: int | None = None) -> list[Contr
141147 # these isn't so important in that case.
142148 return super ().outboxes_for_update (shard_identifier = self .api_application_id or 0 )
143149
150+ def outboxes_for_delete (self ) -> list [ControlOutbox ]:
151+ return [
152+ ControlOutbox (
153+ shard_scope = OutboxScope .APP_SCOPE ,
154+ shard_identifier = self .api_application_id or 0 ,
155+ object_identifier = self .id ,
156+ category = OutboxCategory .SENTRY_APP_INSTALLATION_DELETE ,
157+ region_name = region_name ,
158+ payload = {"uuid" : self .uuid },
159+ )
160+ for region_name in find_all_region_names ()
161+ ]
162+
144163 def prepare_ui_component (
145164 self ,
146165 component : SentryAppComponent ,
0 commit comments