From af1ef4eb8a411a7a6fc41e5eafd2ee0424ad3b3c Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 25 Nov 2025 13:34:56 +0100 Subject: [PATCH 01/13] feat(symbolicator): Consider USE_LOCAL_SYMBOLICATOR for URL rewriting --- src/sentry/lang/native/symbolicator.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sentry/lang/native/symbolicator.py b/src/sentry/lang/native/symbolicator.py index 3d6fa28fc3e84e..92652b7e208b68 100644 --- a/src/sentry/lang/native/symbolicator.py +++ b/src/sentry/lang/native/symbolicator.py @@ -2,6 +2,7 @@ import dataclasses import logging +import os import time import uuid from collections.abc import Callable @@ -547,8 +548,10 @@ def maybe_rewrite_objectstore_url(url: str) -> str: This is needed during development/testing to make Symbolicator reach Objectstore. This is because Sentry can reach Objectstore on 127.0.0.1 but Symbolicator cannot, as it's running in its own container. - Note: if you are using a local (not containerized) instance of Symbolicator, you need to disable this logic. + Set USE_LOCAL_SYMBOLICATOR=1 if you are using a local (not containerized) instance of Symbolicator to disable this rewriting. """ + if os.environ.get("USE_LOCAL_SYMBOLICATOR"): + return url if settings.IS_DEV or in_test_environment(): url = url.replace("127.0.0.1", "objectstore") return url From 0129dec6f8619d02da27b913019023e71a745885 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:35:11 +0100 Subject: [PATCH 02/13] improve --- src/sentry/lang/native/symbolicator.py | 22 +++------------------- src/sentry/objectstore/__init__.py | 14 ++++++++++++++ src/sentry/options/defaults.py | 9 +++++++++ 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/sentry/lang/native/symbolicator.py b/src/sentry/lang/native/symbolicator.py index 92652b7e208b68..78376bc02dc707 100644 --- a/src/sentry/lang/native/symbolicator.py +++ b/src/sentry/lang/native/symbolicator.py @@ -2,7 +2,6 @@ import dataclasses import logging -import os import time import uuid from collections.abc import Callable @@ -27,10 +26,9 @@ 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_session +from sentry.objectstore import get_attachments_session, maybe_rewrite_url from sentry.options.rollout import in_random_rollout from sentry.utils import metrics -from sentry.utils.env import in_test_environment MAX_ATTEMPTS = 3 @@ -200,7 +198,7 @@ def process_minidump( if minidump.stored_id: session = get_attachments_session(self.project.organization_id, self.project.id) storage_url = session.object_url(minidump.stored_id) - storage_url = maybe_rewrite_objectstore_url(storage_url) + storage_url = maybe_rewrite_url(storage_url) json: dict[str, Any] = { "platform": platform, "sources": sources, @@ -246,7 +244,7 @@ def process_applecrashreport(self, platform: str, report: CachedAttachment): if report.stored_id: session = get_attachments_session(self.project.organization_id, self.project.id) storage_url = session.object_url(report.stored_id) - storage_url = maybe_rewrite_objectstore_url(storage_url) + storage_url = maybe_rewrite_url(storage_url) json: dict[str, Any] = { "platform": platform, "sources": sources, @@ -541,17 +539,3 @@ def query_task(self, task_id): def reset_worker_id(self): self.worker_id = uuid.uuid4().hex - - -def maybe_rewrite_objectstore_url(url: str) -> str: - """ - This is needed during development/testing to make Symbolicator reach Objectstore. - This is because Sentry can reach Objectstore on 127.0.0.1 but Symbolicator cannot, as it's running in its own container. - - Set USE_LOCAL_SYMBOLICATOR=1 if you are using a local (not containerized) instance of Symbolicator to disable this rewriting. - """ - if os.environ.get("USE_LOCAL_SYMBOLICATOR"): - return url - if settings.IS_DEV or in_test_environment(): - url = url.replace("127.0.0.1", "objectstore") - return url diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index 83144e48fb69c7..54897f01908e52 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -1,4 +1,5 @@ from datetime import timedelta +from urllib.parse import urlparse, urlunparse from objectstore_client import Client, MetricsBackend, Session, TimeToLive, Usecase from objectstore_client.metrics import Tags @@ -49,3 +50,16 @@ def get_attachments_session(org: int, project: int) -> Session: ) return _ATTACHMENTS_CLIENT.session(_ATTACHMENTS_USECASE, org=org, project=project) + + +def maybe_rewrite_url(url: str) -> str: + from sentry import options + + replacement = options.get("objectstore.host_replacement") + if not replacement: + return url + parsed = urlparse(url) + if parsed.port: + replacement += f":{parsed.port}" + updated = parsed._replace(netloc=replacement) + return urlunparse(updated) diff --git a/src/sentry/options/defaults.py b/src/sentry/options/defaults.py index 950e31fc7fbcbf..5ea946d883fb08 100644 --- a/src/sentry/options/defaults.py +++ b/src/sentry/options/defaults.py @@ -388,6 +388,15 @@ default={"base_url": "http://127.0.0.1:8888"}, flags=FLAG_NOSTORE, ) +# Replacement for the host part of URLs to Objectstore +# This replacement is carried out by the `maybe_rewrite_url` function in `src/sentry/objectstore/__init__.py` +# This should be used for local development and testing, where services can be ran either locally or in containers +# By default, assumes that Sentry runs as a local process while other services run in containers, as in `sentry`'s CI +register( + "objectstore.host_replacement", + default=os.environ.get("SENTRY_OBJECTSTORE_HOST_REPLACEMENT") or "objectstore", + flags=FLAG_NOSTORE, +) # Symbol server From da69cef1aeba46c93bc79753e0cb52e41f5b5fdf Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:36:38 +0100 Subject: [PATCH 03/13] improve --- src/sentry/options/defaults.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sentry/options/defaults.py b/src/sentry/options/defaults.py index 5ea946d883fb08..0eb26dc01e8af9 100644 --- a/src/sentry/options/defaults.py +++ b/src/sentry/options/defaults.py @@ -390,8 +390,9 @@ ) # Replacement for the host part of URLs to Objectstore # This replacement is carried out by the `maybe_rewrite_url` function in `src/sentry/objectstore/__init__.py` -# This should be used for local development and testing, where services can be ran either locally or in containers -# By default, assumes that Sentry runs as a local process while other services run in containers, as in `sentry`'s CI +# This should be used for local development and testing, where services can run either locally or in containers +# By default, assumes that Sentry runs as a local process while other services run in containers +# This is compatible with `sentry`'s CI and generally development workflows using `devservices` register( "objectstore.host_replacement", default=os.environ.get("SENTRY_OBJECTSTORE_HOST_REPLACEMENT") or "objectstore", From b75fda8282d58a16ad5ded6665f4902e374fd690 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:42:13 +0100 Subject: [PATCH 04/13] improve --- src/sentry/options/defaults.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sentry/options/defaults.py b/src/sentry/options/defaults.py index 0eb26dc01e8af9..d20543c14d0efa 100644 --- a/src/sentry/options/defaults.py +++ b/src/sentry/options/defaults.py @@ -1,5 +1,7 @@ import os +from django.conf import settings + from sentry.logging import LoggingFormat from sentry.options import register from sentry.options.manager import ( @@ -16,6 +18,7 @@ FLAG_SCALAR, ) from sentry.quotas.base import build_metric_abuse_quotas +from sentry.utils.env import in_test_environment from sentry.utils.types import Any, Bool, Dict, Float, Int, Sequence, String # Cache @@ -395,7 +398,8 @@ # This is compatible with `sentry`'s CI and generally development workflows using `devservices` register( "objectstore.host_replacement", - default=os.environ.get("SENTRY_OBJECTSTORE_HOST_REPLACEMENT") or "objectstore", + default=os.environ.get("SENTRY_OBJECTSTORE_HOST_REPLACEMENT") + or ("objectstore" if settings.IS_DEV or in_test_environment() else None), flags=FLAG_NOSTORE, ) From 6e22b274201fc4cf13218ee5f1c6fca6cf115759 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:12:50 +0100 Subject: [PATCH 05/13] different approach --- src/sentry/lang/native/symbolicator.py | 8 +++---- src/sentry/objectstore/__init__.py | 29 +++++++++++++++++++------- src/sentry/options/defaults.py | 15 ------------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/sentry/lang/native/symbolicator.py b/src/sentry/lang/native/symbolicator.py index 78376bc02dc707..9217b3cead6859 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_session, maybe_rewrite_url +from sentry.objectstore import get_attachments_session, get_symbolicator_url from sentry.options.rollout import in_random_rollout from sentry.utils import metrics @@ -197,8 +197,7 @@ def process_minidump( if minidump.stored_id: session = get_attachments_session(self.project.organization_id, self.project.id) - storage_url = session.object_url(minidump.stored_id) - storage_url = maybe_rewrite_url(storage_url) + storage_url = get_symbolicator_url(session, minidump.stored_id) json: dict[str, Any] = { "platform": platform, "sources": sources, @@ -243,8 +242,7 @@ def process_applecrashreport(self, platform: str, report: CachedAttachment): if report.stored_id: session = get_attachments_session(self.project.organization_id, self.project.id) - storage_url = session.object_url(report.stored_id) - storage_url = maybe_rewrite_url(storage_url) + storage_url = get_symbolicator_url(session, report.stored_id) json: dict[str, Any] = { "platform": platform, "sources": sources, diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index 54897f01908e52..22294d784cec62 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -1,10 +1,14 @@ +import subprocess from datetime import timedelta from urllib.parse import urlparse, urlunparse +from django.conf import settings from objectstore_client import Client, MetricsBackend, Session, TimeToLive, Usecase from objectstore_client.metrics import Tags +from sentry import options from sentry.utils import metrics as sentry_metrics +from sentry.utils.env import in_test_environment __all__ = ["get_attachments_session"] @@ -41,23 +45,32 @@ def distribution( def get_attachments_session(org: int, project: int) -> Session: global _ATTACHMENTS_CLIENT if not _ATTACHMENTS_CLIENT: - from sentry import options as options_store - - options = options_store.get("objectstore.config") + config = options.get("objectstore.config") _ATTACHMENTS_CLIENT = Client( - options["base_url"], + config["base_url"], metrics_backend=SentryMetricsBackend(), ) return _ATTACHMENTS_CLIENT.session(_ATTACHMENTS_USECASE, org=org, project=project) -def maybe_rewrite_url(url: str) -> str: - from sentry import options +def get_symbolicator_url(session: Session, key: str) -> str: + """Gets the URL that Symbolicator shall use to access the object at the given key in Objectstore.""" - replacement = options.get("objectstore.host_replacement") - if not replacement: + url = session.object_url(key) + if not (settings.IS_DEV or in_test_environment()): return url + + docker_ps = subprocess.run( + ["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True + ) + if docker_ps.returncode != 0: + raise RuntimeError("Failed to run docker ps") + + if "symbolicator" not in docker_ps.stdout: + return url + + replacement = "objectstore" parsed = urlparse(url) if parsed.port: replacement += f":{parsed.port}" diff --git a/src/sentry/options/defaults.py b/src/sentry/options/defaults.py index d20543c14d0efa..cff7b5004bf442 100644 --- a/src/sentry/options/defaults.py +++ b/src/sentry/options/defaults.py @@ -1,7 +1,5 @@ import os -from django.conf import settings - from sentry.logging import LoggingFormat from sentry.options import register from sentry.options.manager import ( @@ -18,7 +16,6 @@ FLAG_SCALAR, ) from sentry.quotas.base import build_metric_abuse_quotas -from sentry.utils.env import in_test_environment from sentry.utils.types import Any, Bool, Dict, Float, Int, Sequence, String # Cache @@ -391,18 +388,6 @@ default={"base_url": "http://127.0.0.1:8888"}, flags=FLAG_NOSTORE, ) -# Replacement for the host part of URLs to Objectstore -# This replacement is carried out by the `maybe_rewrite_url` function in `src/sentry/objectstore/__init__.py` -# This should be used for local development and testing, where services can run either locally or in containers -# By default, assumes that Sentry runs as a local process while other services run in containers -# This is compatible with `sentry`'s CI and generally development workflows using `devservices` -register( - "objectstore.host_replacement", - default=os.environ.get("SENTRY_OBJECTSTORE_HOST_REPLACEMENT") - or ("objectstore" if settings.IS_DEV or in_test_environment() else None), - flags=FLAG_NOSTORE, -) - # Symbol server register( From 78b6866decbce1b42cf14c56bc88230021ba3583 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:14:06 +0100 Subject: [PATCH 06/13] improve --- src/sentry/objectstore/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index 22294d784cec62..097113bba6b570 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -6,7 +6,6 @@ from objectstore_client import Client, MetricsBackend, Session, TimeToLive, Usecase from objectstore_client.metrics import Tags -from sentry import options from sentry.utils import metrics as sentry_metrics from sentry.utils.env import in_test_environment @@ -45,9 +44,11 @@ def distribution( def get_attachments_session(org: int, project: int) -> Session: global _ATTACHMENTS_CLIENT if not _ATTACHMENTS_CLIENT: - config = options.get("objectstore.config") + from sentry import options as options_store + + options = options_store.get("objectstore.config") _ATTACHMENTS_CLIENT = Client( - config["base_url"], + options["base_url"], metrics_backend=SentryMetricsBackend(), ) From cb584afd59bea9b098f283c93d2c42004db51503 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:15:18 +0100 Subject: [PATCH 07/13] improve --- src/sentry/objectstore/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index 097113bba6b570..06de015f2fc36f 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -65,9 +65,6 @@ def get_symbolicator_url(session: Session, key: str) -> str: docker_ps = subprocess.run( ["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True ) - if docker_ps.returncode != 0: - raise RuntimeError("Failed to run docker ps") - if "symbolicator" not in docker_ps.stdout: return url From f95025c613a3cefa3af09d2d57c1d5c77b9c4042 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:16:08 +0100 Subject: [PATCH 08/13] improve --- src/sentry/objectstore/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index 06de015f2fc36f..974029ff89f15a 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -68,6 +68,7 @@ def get_symbolicator_url(session: Session, key: str) -> str: if "symbolicator" not in docker_ps.stdout: return url + # Symbolicator is running in Docker, use the Docker hostname for Objectstore replacement = "objectstore" parsed = urlparse(url) if parsed.port: From 31ac5d1aa821cdd7bdced58b7c6571e617fe86a2 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:18:23 +0100 Subject: [PATCH 09/13] improve --- src/sentry/options/defaults.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sentry/options/defaults.py b/src/sentry/options/defaults.py index cff7b5004bf442..950e31fc7fbcbf 100644 --- a/src/sentry/options/defaults.py +++ b/src/sentry/options/defaults.py @@ -389,6 +389,7 @@ flags=FLAG_NOSTORE, ) + # Symbol server register( "symbolserver.enabled", From 3c9db0a8e092970af8e4fbd660d994cf02d43279 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:28:34 +0100 Subject: [PATCH 10/13] improve --- src/sentry/objectstore/__init__.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index 974029ff89f15a..7738d0e7aee597 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -55,17 +55,25 @@ def get_attachments_session(org: int, project: int) -> Session: return _ATTACHMENTS_CLIENT.session(_ATTACHMENTS_USECASE, org=org, project=project) +_IS_SYMBOLICATOR_CONTAINER: bool | None = None + + def get_symbolicator_url(session: Session, key: str) -> str: """Gets the URL that Symbolicator shall use to access the object at the given key in Objectstore.""" + global _IS_SYMBOLICATOR_CONTAINER url = session.object_url(key) if not (settings.IS_DEV or in_test_environment()): return url - docker_ps = subprocess.run( - ["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True - ) - if "symbolicator" not in docker_ps.stdout: + if _IS_SYMBOLICATOR_CONTAINER is None: + docker_ps = subprocess.run( + ["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True + ) + if "symbolicator" in docker_ps.stdout: + _IS_SYMBOLICATOR_CONTAINER = True + + if not _IS_SYMBOLICATOR_CONTAINER: return url # Symbolicator is running in Docker, use the Docker hostname for Objectstore From 4db25f48f64b029b2bdf526249e6bf870fbadff2 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:32:20 +0100 Subject: [PATCH 11/13] improve --- src/sentry/objectstore/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index 7738d0e7aee597..cf2a590b68bfa3 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -70,8 +70,7 @@ def get_symbolicator_url(session: Session, key: str) -> str: docker_ps = subprocess.run( ["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True ) - if "symbolicator" in docker_ps.stdout: - _IS_SYMBOLICATOR_CONTAINER = True + _IS_SYMBOLICATOR_CONTAINER = "symbolicator" in docker_ps.stdout if not _IS_SYMBOLICATOR_CONTAINER: return url From 2ecd4a9117bf82ad5f407d9fa1bc8da2220c838e Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:47:57 +0100 Subject: [PATCH 12/13] improve --- src/sentry/objectstore/__init__.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index cf2a590b68bfa3..d60ff9f55c0c3e 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -59,23 +59,39 @@ def get_attachments_session(org: int, project: int) -> Session: def get_symbolicator_url(session: Session, key: str) -> str: - """Gets the URL that Symbolicator shall use to access the object at the given key in Objectstore.""" - global _IS_SYMBOLICATOR_CONTAINER + """ + Gets the URL that Symbolicator shall use to access the object at the given key in Objectstore. + + In prod, this is simply the `object_url` returned by `objectstore_client`, as both Sentry and Symbolicator + will talk to Objectstore using the same hostname. + + While in development or testing, we might need to replace the hostname, depending on how Symbolicator is running. + This function runs a `docker ps` to automatically return the correct URL in the following 2 cases: + - Symbolicator running in Docker (possibly via `devservices`): This is the scenario that mirrors `sentry`'s CI. + If this is detected, we replace Objectstore's hostname with the one reachable in the Docker network. + + Note that this approach doesn't work if Objectstore is running both locally and in Docker, as we'll always + rewrite the URL to the Docker one, so Sentry and Symbolicator might attempt to talk to 2 different Objectstores. + - Symbolicator running locally: we don't need to rewrite the URL in that case. + """ + global _IS_SYMBOLICATOR_CONTAINER # Cached to avoid running `docker ps` multiple times url = session.object_url(key) if not (settings.IS_DEV or in_test_environment()): return url if _IS_SYMBOLICATOR_CONTAINER is None: - docker_ps = subprocess.run( - ["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True - ) - _IS_SYMBOLICATOR_CONTAINER = "symbolicator" in docker_ps.stdout + try: + docker_ps = subprocess.run( + ["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True + ) + _IS_SYMBOLICATOR_CONTAINER = "symbolicator" in docker_ps.stdout + except Exception: + _IS_SYMBOLICATOR_CONTAINER = False if not _IS_SYMBOLICATOR_CONTAINER: return url - # Symbolicator is running in Docker, use the Docker hostname for Objectstore replacement = "objectstore" parsed = urlparse(url) if parsed.port: From 74f91a01d57550cb4b2a475e323adfd60cd7bc6f Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:49:29 +0100 Subject: [PATCH 13/13] improve --- src/sentry/objectstore/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sentry/objectstore/__init__.py b/src/sentry/objectstore/__init__.py index d60ff9f55c0c3e..6a27e03027b536 100644 --- a/src/sentry/objectstore/__init__.py +++ b/src/sentry/objectstore/__init__.py @@ -67,12 +67,13 @@ def get_symbolicator_url(session: Session, key: str) -> str: While in development or testing, we might need to replace the hostname, depending on how Symbolicator is running. This function runs a `docker ps` to automatically return the correct URL in the following 2 cases: - - Symbolicator running in Docker (possibly via `devservices`): This is the scenario that mirrors `sentry`'s CI. + - Symbolicator running in Docker (possibly via `devservices`) -- this mirrors `sentry`'s CI. If this is detected, we replace Objectstore's hostname with the one reachable in the Docker network. Note that this approach doesn't work if Objectstore is running both locally and in Docker, as we'll always rewrite the URL to the Docker one, so Sentry and Symbolicator might attempt to talk to 2 different Objectstores. - - Symbolicator running locally: we don't need to rewrite the URL in that case. + - Symbolicator running locally -- this mirrors `symbolicator`'s CI. + In this case, we don't need to rewrite the URL. """ global _IS_SYMBOLICATOR_CONTAINER # Cached to avoid running `docker ps` multiple times