From 26456fccff84e970b75fa7179745077a9e7dfb84 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:46:33 +0100 Subject: [PATCH 1/8] ref(objectstore): Upgrade client to 0.0.9 --- pyproject.toml | 2 +- src/sentry/attachments/__init__.py | 4 ++-- src/sentry/lang/native/symbolicator.py | 18 ++++---------- src/sentry/models/eventattachment.py | 22 +++++++---------- src/sentry/objectstore/__init__.py | 24 ++++++++++--------- src/sentry/reprocessing2.py | 8 ++----- .../test_event_attachment_details.py | 8 +++---- .../test_ingest_consumer_processing.py | 8 +++---- uv.lock | 8 +++---- 9 files changed, 41 insertions(+), 61 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 82eb583e58956c..540e1d8b5d5779 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ dependencies = [ "mmh3>=4.0.0", "msgspec>=0.19.0", "msgpack>=1.1.0", - "objectstore-client>=0.0.5", + "objectstore-client>=0.0.9", "openai>=1.3.5", "orjson>=3.10.10", "packaging>=24.1", diff --git a/src/sentry/attachments/__init__.py b/src/sentry/attachments/__init__.py index 9eabaa957d77ad..0f4edfd97d6187 100644 --- a/src/sentry/attachments/__init__.py +++ b/src/sentry/attachments/__init__.py @@ -16,7 +16,7 @@ from django.conf import settings from sentry.objectstore import Client as ObjectstoreClient -from sentry.objectstore import get_attachments_client +from sentry.objectstore import get_attachments_session from sentry.options.rollout import in_random_rollout from sentry.utils.cache import cache_key_for_event from sentry.utils.imports import import_string @@ -86,7 +86,7 @@ def delete_cached_and_ratelimited_attachments( # deletes from objectstore if no long-term storage is desired if attachment.rate_limited and attachment.stored_id: if client is None: - client = get_attachments_client().for_project(project.organization_id, project.id) + client = get_attachments_session(project.organization_id, project.id) client.delete(attachment.stored_id) # unconditionally deletes any payloads from the attachment cache diff --git a/src/sentry/lang/native/symbolicator.py b/src/sentry/lang/native/symbolicator.py index 78be8cc3ccc0be..ebc5849b75f119 100644 --- a/src/sentry/lang/native/symbolicator.py +++ b/src/sentry/lang/native/symbolicator.py @@ -26,7 +26,7 @@ from sentry.lang.native.utils import Backoff from sentry.models.project import Project from sentry.net.http import Session -from sentry.objectstore import get_attachments_client +from sentry.objectstore import get_attachments_session from sentry.options.rollout import in_random_rollout from sentry.utils import metrics @@ -180,15 +180,11 @@ def process_minidump( "objectstore.force-stored-symbolication" ) if force_stored_attachment: - client = get_attachments_client().for_project( - self.project.organization_id, self.project.id - ) + client = get_attachments_session(self.project.organization_id, self.project.id) minidump.stored_id = client.put(minidump.data) if minidump.stored_id: - client = get_attachments_client().for_project( - self.project.organization_id, self.project.id - ) + client = get_attachments_session(self.project.organization_id, self.project.id) storage_url = client.object_url(minidump.stored_id) json: dict[str, Any] = { "platform": platform, @@ -229,15 +225,11 @@ def process_applecrashreport(self, platform: str, report: CachedAttachment): "objectstore.force-stored-symbolication" ) if force_stored_attachment: - client = get_attachments_client().for_project( - self.project.organization_id, self.project.id - ) + client = get_attachments_session(self.project.organization_id, self.project.id) report.stored_id = client.put(report.data) if report.stored_id: - client = get_attachments_client().for_project( - self.project.organization_id, self.project.id - ) + client = get_attachments_session(self.project.organization_id, self.project.id) storage_url = client.object_url(report.stored_id) json: dict[str, Any] = { "platform": platform, diff --git a/src/sentry/models/eventattachment.py b/src/sentry/models/eventattachment.py index 1e5bab96d939a1..763ccd00cc0c1f 100644 --- a/src/sentry/models/eventattachment.py +++ b/src/sentry/models/eventattachment.py @@ -18,7 +18,7 @@ from sentry.db.models.fields.bounded import BoundedIntegerField from sentry.db.models.manager.base_query_set import BaseQuerySet from sentry.models.files.utils import get_size_and_checksum, get_storage -from sentry.objectstore import get_attachments_client +from sentry.objectstore import get_attachments_session from sentry.objectstore.metrics import measure_storage_operation from sentry.options.rollout import in_random_rollout from sentry.utils import metrics @@ -130,15 +130,15 @@ def delete(self, *args: Any, **kwargs: Any) -> tuple[int, dict[str, int]]: if blob_path.startswith(V2_PREFIX): try: organization_id = _get_organization(self.project_id) - get_attachments_client().for_project( - organization_id, self.project_id - ).delete(blob_path.removeprefix(V2_PREFIX)) + get_attachments_session(organization_id, self.project_id).delete( + blob_path.removeprefix(V2_PREFIX) + ) except Exception: sentry_sdk.capture_exception() elif self.blob_path.startswith(V2_PREFIX): organization_id = _get_organization(self.project_id) - get_attachments_client().for_project(organization_id, self.project_id).delete( + get_attachments_session(organization_id, self.project_id).delete( self.blob_path.removeprefix(V2_PREFIX) ) @@ -169,9 +169,7 @@ def getfile(self) -> IO[bytes]: elif self.blob_path.startswith(V2_PREFIX): id = self.blob_path.removeprefix(V2_PREFIX) organization_id = _get_organization(self.project_id) - response = ( - get_attachments_client().for_project(organization_id, self.project_id).get(id) - ) + response = get_attachments_session(organization_id, self.project_id).get(id) return response.payload raise NotImplementedError() @@ -203,9 +201,7 @@ def putfile(cls, project_id: int, attachment: CachedAttachment) -> PutfileResult if in_random_rollout("objectstore.double_write.attachments"): try: organization_id = _get_organization(project_id) - get_attachments_client().for_project(organization_id, project_id).put( - data, id=object_key - ) + get_attachments_session(organization_id, project_id).put(data, id=object_key) metrics.incr("storage.attachments.double_write") blob_path += V2_PREFIX except Exception: @@ -220,9 +216,7 @@ def putfile(cls, project_id: int, attachment: CachedAttachment) -> PutfileResult else: organization_id = _get_organization(project_id) - blob_path = V2_PREFIX + get_attachments_client().for_project( - organization_id, project_id - ).put(data) + blob_path = V2_PREFIX + get_attachments_session(organization_id, project_id).put(data) return PutfileResult( content_type=content_type, size=size, sha1=checksum, blob_path=blob_path diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index ead6115fcedec2..f6395c1ce3ae99 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -1,13 +1,11 @@ from datetime import timedelta -from objectstore_client import Client, ClientBuilder, ClientError, MetricsBackend, TimeToLive +from objectstore_client import Client, MetricsBackend, Session, TimeToLive, Usecase from objectstore_client.metrics import Tags from sentry.utils import metrics as sentry_metrics -__all__ = ["get_attachments_client", "Client", "ClientBuilder", "ClientError"] - -_attachments_client: ClientBuilder | None = None +__all__ = ["get_attachments_session"] class SentryMetricsBackend(MetricsBackend): @@ -35,16 +33,20 @@ def distribution( sentry_metrics.distribution(name, value, tags=tags, unit=unit) -def get_attachments_client() -> ClientBuilder: - global _attachments_client - if not _attachments_client: +_ATTACHMENTS = Usecase("attachments", expiration_policy=TimeToLive(timedelta(days=30))) +_ATTACHMENTS_SESSION: Session | None = None + + +def get_attachments_session(org: int, project: int) -> Session: + global _ATTACHMENTS_SESSION + if not _ATTACHMENTS_SESSION: from sentry import options as options_store options = options_store.get("objectstore.config") - _attachments_client = ClientBuilder( + client = Client( options["base_url"], - "attachments", metrics_backend=SentryMetricsBackend(), - default_expiration_policy=TimeToLive(timedelta(days=30)), ) - return _attachments_client + _ATTACHMENTS_SESSION = client.session(_ATTACHMENTS, org=org, project=project) + + return _ATTACHMENTS_SESSION diff --git a/src/sentry/reprocessing2.py b/src/sentry/reprocessing2.py index a6a3b8233ed2a8..bf074bb14c9787 100644 --- a/src/sentry/reprocessing2.py +++ b/src/sentry/reprocessing2.py @@ -97,7 +97,7 @@ from sentry.models.eventattachment import V1_PREFIX, V2_PREFIX, EventAttachment from sentry.models.files.utils import get_storage from sentry.models.project import Project -from sentry.objectstore import get_attachments_client +from sentry.objectstore import get_attachments_session from sentry.options.rollout import in_random_rollout from sentry.services import eventstore from sentry.services.eventstore.models import Event, GroupEvent @@ -412,11 +412,7 @@ def _maybe_copy_attachment_into_cache( else: # otherwise, we store it in objectstore with attachment.getfile() as fp: - stored_id = ( - get_attachments_client() - .for_project(project.organization_id, project.id) - .put(fp) - ) + stored_id = get_attachments_session(project.organization_id, project.id).put(fp) # but we then also make that storage permanent, as otherwise # the codepaths won’t be cleaning up this stored file. # essentially this means we are moving the file from the previous storage diff --git a/tests/sentry/api/endpoints/test_event_attachment_details.py b/tests/sentry/api/endpoints/test_event_attachment_details.py index 8ed840f5abde04..2de27274936ab2 100644 --- a/tests/sentry/api/endpoints/test_event_attachment_details.py +++ b/tests/sentry/api/endpoints/test_event_attachment_details.py @@ -4,7 +4,7 @@ from sentry.attachments.base import CachedAttachment from sentry.models.activity import Activity from sentry.models.eventattachment import V1_PREFIX, V2_PREFIX, EventAttachment -from sentry.objectstore import get_attachments_client +from sentry.objectstore import get_attachments_session from sentry.testutils.cases import APITestCase, PermissionTestCase, TestCase from sentry.testutils.helpers.datetime import before_now from sentry.testutils.helpers.features import with_feature @@ -97,10 +97,8 @@ def test_doublewrite_objectstore(self) -> None: assert attachment.blob_path is not None object_key = attachment.blob_path.removeprefix(V1_PREFIX + V2_PREFIX) # the file should also be available in objectstore - os_response = ( - get_attachments_client() - .for_project(self.organization.id, self.project.id) - .get(object_key) + os_response = get_attachments_session(self.organization.id, self.project.id).get( + object_key ) assert os_response.payload.read() == ATTACHMENT_CONTENT diff --git a/tests/sentry/ingest/ingest_consumer/test_ingest_consumer_processing.py b/tests/sentry/ingest/ingest_consumer/test_ingest_consumer_processing.py index a67cc8fe7a194d..72319419751e1c 100644 --- a/tests/sentry/ingest/ingest_consumer/test_ingest_consumer_processing.py +++ b/tests/sentry/ingest/ingest_consumer/test_ingest_consumer_processing.py @@ -29,7 +29,7 @@ from sentry.models.debugfile import create_files_from_dif_zip from sentry.models.eventattachment import EventAttachment from sentry.models.userreport import UserReport -from sentry.objectstore import get_attachments_client +from sentry.objectstore import get_attachments_session from sentry.services import eventstore from sentry.testutils.factories import get_fixture_path from sentry.testutils.helpers.features import Feature @@ -467,10 +467,8 @@ def test_process_stored_attachment( with open(get_fixture_path("native", "threadnames.dmp"), "rb") as f: attachment_payload = f.read() - stored_id = ( - get_attachments_client() - .for_project(default_project.organization_id, project_id) - .put(attachment_payload) + stored_id = get_attachments_session(default_project.organization_id, project_id).put( + attachment_payload ) with task_runner(): diff --git a/uv.lock b/uv.lock index cf666eb7048b98..34a90d2feeb2b7 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.13" resolution-markers = [ "sys_platform == 'darwin' or sys_platform == 'linux'", @@ -1159,7 +1159,7 @@ wheels = [ [[package]] name = "objectstore-client" -version = "0.0.5" +version = "0.0.9" source = { registry = "https://pypi.devinfra.sentry.io/simple" } dependencies = [ { name = "sentry-sdk", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, @@ -1167,7 +1167,7 @@ dependencies = [ { name = "zstandard", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, ] wheels = [ - { url = "https://pypi.devinfra.sentry.io/wheels/objectstore_client-0.0.5-py3-none-any.whl", hash = "sha256:80f069d48b325f0420f7bfc3cbddca3fa86012761ff462e0145664e3a206e907" }, + { url = "https://pypi.devinfra.sentry.io/wheels/objectstore_client-0.0.9-py3-none-any.whl", hash = "sha256:48fe6c651b73ab18da9b4fb15a81d0b3aeae96115c7f1b6776f03022d6bb5f44" }, ] [[package]] @@ -2135,7 +2135,7 @@ requires-dist = [ { name = "mmh3", specifier = ">=4.0.0" }, { name = "msgpack", specifier = ">=1.1.0" }, { name = "msgspec", specifier = ">=0.19.0" }, - { name = "objectstore-client", specifier = ">=0.0.5" }, + { name = "objectstore-client", specifier = ">=0.0.9" }, { name = "openai", specifier = ">=1.3.5" }, { name = "orjson", specifier = ">=3.10.10" }, { name = "packaging", specifier = ">=24.1" }, From 7155b96577de0d42ba840debdf94920c8d4b8880 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:50:26 +0100 Subject: [PATCH 2/8] improve --- src/sentry/lang/native/symbolicator.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sentry/lang/native/symbolicator.py b/src/sentry/lang/native/symbolicator.py index ebc5849b75f119..0567dbd617abed 100644 --- a/src/sentry/lang/native/symbolicator.py +++ b/src/sentry/lang/native/symbolicator.py @@ -180,12 +180,12 @@ def process_minidump( "objectstore.force-stored-symbolication" ) if force_stored_attachment: - client = get_attachments_session(self.project.organization_id, self.project.id) - minidump.stored_id = client.put(minidump.data) + session = get_attachments_session(self.project.organization_id, self.project.id) + minidump.stored_id = session.put(minidump.data) if minidump.stored_id: - client = get_attachments_session(self.project.organization_id, self.project.id) - storage_url = client.object_url(minidump.stored_id) + session = get_attachments_session(self.project.organization_id, self.project.id) + storage_url = session.object_url(minidump.stored_id) json: dict[str, Any] = { "platform": platform, "sources": sources, @@ -202,7 +202,7 @@ def process_minidump( return process_response(res) finally: if force_stored_attachment: - client.delete(minidump.stored_id) + session.delete(minidump.stored_id) minidump.stored_id = None data = { @@ -225,12 +225,12 @@ def process_applecrashreport(self, platform: str, report: CachedAttachment): "objectstore.force-stored-symbolication" ) if force_stored_attachment: - client = get_attachments_session(self.project.organization_id, self.project.id) - report.stored_id = client.put(report.data) + session = get_attachments_session(self.project.organization_id, self.project.id) + report.stored_id = session.put(report.data) if report.stored_id: - client = get_attachments_session(self.project.organization_id, self.project.id) - storage_url = client.object_url(report.stored_id) + session = get_attachments_session(self.project.organization_id, self.project.id) + storage_url = session.object_url(report.stored_id) json: dict[str, Any] = { "platform": platform, "sources": sources, @@ -246,7 +246,7 @@ def process_applecrashreport(self, platform: str, report: CachedAttachment): return process_response(res) finally: if force_stored_attachment: - client.delete(report.stored_id) + session.delete(report.stored_id) report.stored_id = None data = { From d27c61c0c0e1411df377b35c4be7b6cc9f04294e Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:58:41 +0100 Subject: [PATCH 3/8] improve --- src/sentry/objectstore/__init__.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index f6395c1ce3ae99..83144e48fb69c7 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -33,20 +33,19 @@ def distribution( sentry_metrics.distribution(name, value, tags=tags, unit=unit) -_ATTACHMENTS = Usecase("attachments", expiration_policy=TimeToLive(timedelta(days=30))) -_ATTACHMENTS_SESSION: Session | None = None +_ATTACHMENTS_CLIENT: Client | None = None +_ATTACHMENTS_USECASE = Usecase("attachments", expiration_policy=TimeToLive(timedelta(days=30))) def get_attachments_session(org: int, project: int) -> Session: - global _ATTACHMENTS_SESSION - if not _ATTACHMENTS_SESSION: + global _ATTACHMENTS_CLIENT + if not _ATTACHMENTS_CLIENT: from sentry import options as options_store options = options_store.get("objectstore.config") - client = Client( + _ATTACHMENTS_CLIENT = Client( options["base_url"], metrics_backend=SentryMetricsBackend(), ) - _ATTACHMENTS_SESSION = client.session(_ATTACHMENTS, org=org, project=project) - return _ATTACHMENTS_SESSION + return _ATTACHMENTS_CLIENT.session(_ATTACHMENTS_USECASE, org=org, project=project) From e9599b4696a8f2ec3d2d1c58b9a47738c9dfa8c7 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Fri, 14 Nov 2025 17:21:07 +0100 Subject: [PATCH 4/8] improve --- src/sentry/attachments/__init__.py | 8 +-- tests/sentry/objectstore/test_objectstore.py | 71 -------------------- 2 files changed, 3 insertions(+), 76 deletions(-) delete mode 100644 tests/sentry/objectstore/test_objectstore.py diff --git a/src/sentry/attachments/__init__.py b/src/sentry/attachments/__init__.py index 0f4edfd97d6187..a0cb6557d04204 100644 --- a/src/sentry/attachments/__init__.py +++ b/src/sentry/attachments/__init__.py @@ -15,7 +15,6 @@ import sentry_sdk from django.conf import settings -from sentry.objectstore import Client as ObjectstoreClient from sentry.objectstore import get_attachments_session from sentry.options.rollout import in_random_rollout from sentry.utils.cache import cache_key_for_event @@ -81,13 +80,12 @@ def delete_cached_and_ratelimited_attachments( Non-ratelimited attachments which are already stored in `objectstore` will be retained there for long-term storage. """ - client: ObjectstoreClient | None = None for attachment in attachments: # deletes from objectstore if no long-term storage is desired if attachment.rate_limited and attachment.stored_id: - if client is None: - client = get_attachments_session(project.organization_id, project.id) - client.delete(attachment.stored_id) + get_attachments_session(project.organization_id, project.id).delete( + attachment.stored_id + ) # unconditionally deletes any payloads from the attachment cache attachment.delete() diff --git a/tests/sentry/objectstore/test_objectstore.py b/tests/sentry/objectstore/test_objectstore.py deleted file mode 100644 index 7c7d0881bec385..00000000000000 --- a/tests/sentry/objectstore/test_objectstore.py +++ /dev/null @@ -1,71 +0,0 @@ -import pytest -import zstandard - -from sentry.objectstore import ClientBuilder, ClientError -from sentry.testutils.skips import requires_objectstore - -pytestmark = [requires_objectstore] - - -class Testserver: - url = "http://localhost:8888" - secret = "" - - -def test_object_url() -> None: - server = Testserver() - client = ClientBuilder(server.url, "test").for_project(123, 456) - - assert ( - client.object_url("foo") - == "http://localhost:8888/v1/foo?usecase=test&scope=org.123%2Fproj.456" - ) - - -def test_stores_uncompressed() -> None: - server = Testserver() - client = ClientBuilder(server.url, "test").for_organization(12345) - - body = b"oh hai!" - stored_id = client.put(body, "foo", compression="none") - assert stored_id == "foo" - - result = client.get("foo") - - assert result.metadata.compression is None - assert result.payload.read() == b"oh hai!" - - -def test_uses_zstd_by_default() -> None: - server = Testserver() - client = ClientBuilder(server.url, "test").for_organization(12345) - - body = b"oh hai!" - stored_id = client.put(body, "foo") - assert stored_id == "foo" - - # when the user indicates that it does not want decompression, it gets zstd - result = client.get("foo", decompress=False) - - assert result.metadata.compression == "zstd" - assert zstandard.decompress(result.payload.read(), 1024) == b"oh hai!" - - # otherwise, the client does the decompression - result = client.get("foo") - - assert result.metadata.compression is None - assert result.payload.read() == b"oh hai!" - - -def test_deletes_stored_stuff() -> None: - server = Testserver() - client = ClientBuilder(server.url, "test").for_organization(12345) - - body = b"oh hai!" - stored_id = client.put(body, "foo") - assert stored_id == "foo" - - client.delete("foo") - - with pytest.raises(ClientError): - client.get("foo") From 009ce6224908dd9b5d470aea83158a20047e7bfa Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Fri, 14 Nov 2025 17:24:06 +0100 Subject: [PATCH 5/8] remove tests from pyproject.toml --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 540e1d8b5d5779..29588e3995d126 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -797,7 +797,6 @@ module = [ "tests.sentry.notifications.notifications.organization_request.*", "tests.sentry.notifications.platform.*", "tests.sentry.notifications.utils.*", - "tests.sentry.objectstore.*", "tests.sentry.onboarding_tasks.*", "tests.sentry.organizations.*", "tests.sentry.partnerships.*", From 440013b2f7b4be747f4c79f190ecf69342bc0387 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Fri, 14 Nov 2025 17:42:37 +0100 Subject: [PATCH 6/8] bump to 0.0.10 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index cc91b3a70578fc..98b8774849d3eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ dependencies = [ "mmh3>=4.0.0", "msgspec>=0.19.0", "msgpack>=1.1.0", - "objectstore-client>=0.0.9", + "objectstore-client>=0.0.10", "openai>=1.3.5", "orjson>=3.10.10", "packaging>=24.1", From 2a6588dc8d40f7e22a2c2589bc6b76b802bb9ca2 Mon Sep 17 00:00:00 2001 From: "getsantry[bot]" <66042841+getsantry[bot]@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:54:28 +0000 Subject: [PATCH 7/8] :snowflake: re-freeze requirements --- uv.lock | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index 570039b43edbc7..3dda25fc0a9113 100644 --- a/uv.lock +++ b/uv.lock @@ -439,6 +439,14 @@ wheels = [ { url = "https://pypi.devinfra.sentry.io/wheels/filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c" }, ] +[[package]] +name = "filetype" +version = "1.2.0" +source = { registry = "https://pypi.devinfra.sentry.io/simple" } +wheels = [ + { url = "https://pypi.devinfra.sentry.io/wheels/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25" }, +] + [[package]] name = "flake8" version = "7.3.0" @@ -1159,15 +1167,16 @@ wheels = [ [[package]] name = "objectstore-client" -version = "0.0.9" +version = "0.0.10" source = { registry = "https://pypi.devinfra.sentry.io/simple" } dependencies = [ + { name = "filetype", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "sentry-sdk", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "urllib3", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, { name = "zstandard", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" }, ] wheels = [ - { url = "https://pypi.devinfra.sentry.io/wheels/objectstore_client-0.0.9-py3-none-any.whl", hash = "sha256:48fe6c651b73ab18da9b4fb15a81d0b3aeae96115c7f1b6776f03022d6bb5f44" }, + { url = "https://pypi.devinfra.sentry.io/wheels/objectstore_client-0.0.10-py3-none-any.whl", hash = "sha256:464718f1ff3678c522e9bfa26619715801784eabd187e9d7066171f0e617f3ad" }, ] [[package]] @@ -2135,7 +2144,7 @@ requires-dist = [ { name = "mmh3", specifier = ">=4.0.0" }, { name = "msgpack", specifier = ">=1.1.0" }, { name = "msgspec", specifier = ">=0.19.0" }, - { name = "objectstore-client", specifier = ">=0.0.9" }, + { name = "objectstore-client", specifier = ">=0.0.10" }, { name = "openai", specifier = ">=1.3.5" }, { name = "orjson", specifier = ">=3.10.10" }, { name = "packaging", specifier = ">=24.1" }, From 9aa156b8c5cf5484d758afc70ed1c7178d783334 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Fri, 14 Nov 2025 18:02:37 +0100 Subject: [PATCH 8/8] id -> key --- src/sentry/models/eventattachment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/models/eventattachment.py b/src/sentry/models/eventattachment.py index 763ccd00cc0c1f..aa6807eb503ec4 100644 --- a/src/sentry/models/eventattachment.py +++ b/src/sentry/models/eventattachment.py @@ -201,7 +201,7 @@ def putfile(cls, project_id: int, attachment: CachedAttachment) -> PutfileResult if in_random_rollout("objectstore.double_write.attachments"): try: organization_id = _get_organization(project_id) - get_attachments_session(organization_id, project_id).put(data, id=object_key) + get_attachments_session(organization_id, project_id).put(data, key=object_key) metrics.incr("storage.attachments.double_write") blob_path += V2_PREFIX except Exception: