-
-
Notifications
You must be signed in to change notification settings - Fork 4.9k
feat(preprod): Read snapshot objectstore content from both usecases #124194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
885b4af
4b9c892
0787390
ae68c16
5310992
0b8d48c
03d1484
8b9083d
1a6f384
a8cf770
f567b26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import IO, Literal | ||
|
|
||
| from objectstore_client import Compression, GetResponse, Metadata, RequestError, Session | ||
| from objectstore_client.multipart import MultipartUpload | ||
| from urllib3.exceptions import HTTPError | ||
|
|
||
| from sentry.models.project import Project | ||
| from sentry.objectstore import UsecaseId, get_session | ||
| from sentry.utils import metrics | ||
|
|
||
|
|
||
| # TODO: On January 1, 2027, remove the preprod fallback and use preprod_snapshots exclusively. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? Is the date meaningful or just a "far enough in the future" reminder?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the default retention is 90 days. so it's a bit more than 90 days and simple heh i will cut a linear ticket as a reminder for this too
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| class SnapshotStorage: | ||
| def __init__(self, primary: Session, fallback: Session) -> None: | ||
| self._primary = primary | ||
| self._fallback = fallback | ||
|
|
||
| def get(self, key: str) -> GetResponse | None: | ||
| response = self._primary.get(key) | ||
| if response is None: | ||
| response = self._fallback.get(key) | ||
| self._record_fallback("get", response is not None) | ||
| return response | ||
|
|
||
| def head(self, key: str) -> Metadata | None: | ||
| metadata = self._primary.head(key) | ||
| if metadata is None: | ||
| metadata = self._fallback.head(key) | ||
| self._record_fallback("head", metadata is not None) | ||
| return metadata | ||
|
|
||
| def _record_fallback(self, op: str, found: bool) -> None: | ||
| metrics.incr( | ||
| "preprod.snapshot_storage.legacy_fallback", | ||
| tags={"op": op, "found": str(found).lower()}, | ||
| ) | ||
|
|
||
| def put(self, contents: bytes | IO[bytes], *, key: str, content_type: str | None = None) -> str: | ||
| return self._primary.put(contents, key=key, content_type=content_type) | ||
|
|
||
| def initiate_multipart_upload( | ||
| self, *, key: str, compression: Compression | Literal["none"], content_type: str | ||
| ) -> MultipartUpload: | ||
| return self._primary.initiate_multipart_upload( | ||
| key=key, compression=compression, content_type=content_type | ||
| ) | ||
|
|
||
| def delete(self, key: str) -> None: | ||
| error: RequestError | HTTPError | None = None | ||
| for session in (self._primary, self._fallback): | ||
| try: | ||
| session.delete(key) | ||
| except (RequestError, HTTPError) as caught_error: | ||
| if error is None and ( | ||
| not isinstance(caught_error, RequestError) or caught_error.status != 404 | ||
| ): | ||
| error = caught_error | ||
| if error is not None: | ||
| raise error | ||
|
|
||
|
|
||
| def get_snapshot_storage(project: Project | int, *, org: int | None = None) -> SnapshotStorage: | ||
| return SnapshotStorage( | ||
| primary=get_session(UsecaseId.PREPROD, project, org=org), | ||
| fallback=get_session(UsecaseId.PREPROD_SNAPSHOTS, project, org=org), | ||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is preprod the only consumer of this type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes