Skip to content

Commit 87208ad

Browse files
committed
Remove File-based EventAttachment code
Already 17 months ago in #62318, I switched the `EventAttachment` code over from using the `file_id` and django `File`-models to storing things in filestore (the go service) directly via the `blob_path`. As attachments have a 30 day TTL, it is high time to remove the backwards compatibility code.
1 parent 84dbaa5 commit 87208ad

File tree

3 files changed

+14
-46
lines changed

3 files changed

+14
-46
lines changed

src/sentry/event_manager.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2372,7 +2372,6 @@ def save_attachment(
23722372
size=file.size,
23732373
sha1=file.sha1,
23742374
# storage:
2375-
file_id=file.file_id,
23762375
blob_path=file.blob_path,
23772376
)
23782377

src/sentry/models/eventattachment.py

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import zstandard
1010
from django.core.cache import cache
11-
from django.core.exceptions import ObjectDoesNotExist
1211
from django.db import models
1312
from django.utils import timezone
1413

@@ -42,7 +41,6 @@ class PutfileResult:
4241
content_type: str
4342
size: int
4443
sha1: str
45-
file_id: int | None = None
4644
blob_path: str | None = None
4745

4846

@@ -61,8 +59,7 @@ class EventAttachment(Model):
6159
"""Attachment Metadata and Storage
6260
6361
The actual attachment data can be saved in different backing stores:
64-
- Using the :class:`File` model using the `file_id` field.
65-
This stores attachments chunked and deduplicated.
62+
- When the attachment is empty (0-size), `blob_path is None`.
6663
- When the `blob_path` field has a `:` prefix:
6764
It is saved inline in `blob_path` following the `:` prefix.
6865
This happens for "small" and ASCII-only (see `can_store_inline`) attachments.
@@ -88,8 +85,7 @@ class EventAttachment(Model):
8885

8986
date_added = models.DateTimeField(default=timezone.now, db_index=True)
9087

91-
# the backing blob, either going through the `File` model,
92-
# or directly to a backing blob store
88+
# The `file_id` will be removed in a multi-part migration soon.
9389
file_id = BoundedBigIntegerField(null=True, db_index=True)
9490
blob_path = models.TextField(null=True)
9591

@@ -114,51 +110,29 @@ def delete(self, *args: Any, **kwargs: Any) -> tuple[int, dict[str, int]]:
114110

115111
if self.blob_path:
116112
if self.blob_path.startswith(":"):
117-
return rv
113+
pass # nothing to do for inline-stored attachments
118114
elif self.blob_path.startswith("eventattachments/v1/"):
119115
storage = get_storage()
116+
storage.delete(self.blob_path)
120117
else:
121118
raise NotImplementedError()
122119

123-
storage.delete(self.blob_path)
124-
return rv
125-
126-
try:
127-
from sentry.models.files.file import File
128-
129-
file = File.objects.get(id=self.file_id)
130-
except ObjectDoesNotExist:
131-
# It's possible that the File itself was deleted
132-
# before we were deleted when the object is in memory
133-
# This seems to be a case that happens during deletion
134-
# code.
135-
pass
136-
else:
137-
file.delete()
138-
139120
return rv
140121

141122
def getfile(self) -> IO[bytes]:
142-
if self.size == 0:
123+
if not self.blob_path:
143124
return BytesIO(b"")
144125

145-
if self.blob_path:
146-
if self.blob_path.startswith(":"):
147-
return BytesIO(self.blob_path[1:].encode())
148-
149-
elif self.blob_path.startswith("eventattachments/v1/"):
150-
storage = get_storage()
151-
compressed_blob = storage.open(self.blob_path)
152-
dctx = zstandard.ZstdDecompressor()
153-
return dctx.stream_reader(compressed_blob, read_across_frames=True)
126+
if self.blob_path.startswith(":"):
127+
return BytesIO(self.blob_path[1:].encode())
154128

155-
else:
156-
raise NotImplementedError()
157-
158-
from sentry.models.files.file import File
129+
elif self.blob_path.startswith("eventattachments/v1/"):
130+
storage = get_storage()
131+
compressed_blob = storage.open(self.blob_path)
132+
dctx = zstandard.ZstdDecompressor()
133+
return dctx.stream_reader(compressed_blob, read_across_frames=True)
159134

160-
file = File.objects.get(id=self.file_id)
161-
return file.getfile()
135+
raise NotImplementedError()
162136

163137
@classmethod
164138
def putfile(cls, project_id: int, attachment: CachedAttachment) -> PutfileResult:
@@ -171,7 +145,6 @@ def putfile(cls, project_id: int, attachment: CachedAttachment) -> PutfileResult
171145
return PutfileResult(content_type=content_type, size=0, sha1=sha1().hexdigest())
172146

173147
blob = BytesIO(data)
174-
175148
size, checksum = get_size_and_checksum(blob)
176149

177150
if can_store_inline(data):

tests/sentry/api/endpoints/test_event_attachment_details.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,7 @@ def create_attachment(self, content: bytes | None = None, group_id: int | None =
3535
attachment = CachedAttachment(
3636
name="hello.png", content_type="image/png; foo=bar", data=data
3737
)
38-
file = EventAttachment.putfile(
39-
self.project.id,
40-
attachment,
41-
)
38+
file = EventAttachment.putfile(self.project.id, attachment)
4239

4340
self.attachment = EventAttachment.objects.create(
4441
event_id=self.event.event_id,
@@ -50,7 +47,6 @@ def create_attachment(self, content: bytes | None = None, group_id: int | None =
5047
size=file.size,
5148
sha1=file.sha1,
5249
# storage:
53-
file_id=file.file_id,
5450
blob_path=file.blob_path,
5551
)
5652

0 commit comments

Comments
 (0)