From dd58c408dae01af699195e99b1312c2e6374a499 Mon Sep 17 00:00:00 2001 From: ATC964 <82515918+atc964@users.noreply.github.com> Date: Wed, 24 Jun 2026 12:27:08 -0400 Subject: [PATCH 1/2] Disable crewai/chromadb/posthog telemetry at import + force-exit CLI (ar-r82f.21) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit crewai 1.14.6 transitively launches daemon threads from chromadb and posthog that don't honor any documented opt-out env var at shutdown. Result: CLI commands hang ~5 minutes on interpreter exit after running. Discovered 2026-05-29 during EOD smoke test (ar-r82f.15). Workaround verified to drop shutdown time from ~5 min to <2s. Two pieces: - _telemetry_shim.py: sets 8 documented opt-out env vars at import time, before crewai/chromadb/posthog get loaded transitively - CLI main: wraps typer app() with os._exit(0) to bypass any lingering atexit handlers that snuck through The shim is conservative — env-var-only, no monkey-patching. The os._exit(0) wrapper only applies to the CLI entry point (uvicorn/ FastAPI servers stay on their normal exit path). bead: ar-r82f.21 --- src/ad_seller/__init__.py | 2 ++ src/ad_seller/_telemetry_shim.py | 51 ++++++++++++++++++++++++++++ src/ad_seller/interfaces/cli/main.py | 8 ++++- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/ad_seller/_telemetry_shim.py diff --git a/src/ad_seller/__init__.py b/src/ad_seller/__init__.py index 98b2f3f..54a5f0e 100644 --- a/src/ad_seller/__init__.py +++ b/src/ad_seller/__init__.py @@ -3,4 +3,6 @@ """Ad Seller System - IAB OpenDirect 2.1 compliant publisher/SSP agent system.""" +from ad_seller import _telemetry_shim # noqa: F401 # MUST be first import — ar-r82f.21 + __version__ = "0.1.0" diff --git a/src/ad_seller/_telemetry_shim.py b/src/ad_seller/_telemetry_shim.py new file mode 100644 index 0000000..d0ebb39 --- /dev/null +++ b/src/ad_seller/_telemetry_shim.py @@ -0,0 +1,51 @@ +"""Telemetry / shutdown shim for crewai 1.14.6 (ar-r82f.21). + +Sets opt-out env vars *before* any crewai / chromadb / posthog / opentelemetry +import path runs, so their constructors take the disabled branch instead of +registering daemon threads and atexit handlers that hang the interpreter for +~5 minutes on shutdown. + +This module must be imported BEFORE crewai. The `ad_seller/__init__.py` imports +it as the very first statement. + +CLI entrypoints additionally call `os._exit(0)` after `app()` returns to bypass +any straggling atexit handlers that snuck in via transitive deps. +""" + +from __future__ import annotations + +import os + +_TELEMETRY_ENV = { + "OTEL_SDK_DISABLED": "true", + "CREWAI_DISABLE_TELEMETRY": "true", + "CREWAI_DISABLE_TRACKING": "true", + "CREWAI_TELEMETRY_OPT_OUT": "true", + "ANONYMIZED_TELEMETRY": "false", + "POSTHOG_DISABLED": "true", + "CHROMA_TELEMETRY_DISABLED": "true", + "DO_NOT_TRACK": "1", +} + +for _k, _v in _TELEMETRY_ENV.items(): + os.environ.setdefault(_k, _v) + + +def force_exit_after(callable_): + """Wrap a typer/click entrypoint so the process hard-exits on return. + + Usage in CLI main: + if __name__ == "__main__": + force_exit_after(app)() + """ + + def _wrapped(*args, **kwargs): + try: + result = callable_(*args, **kwargs) + os._exit(0) + return result + except SystemExit as e: + code = e.code if isinstance(e.code, int) else 0 + os._exit(code) + + return _wrapped diff --git a/src/ad_seller/interfaces/cli/main.py b/src/ad_seller/interfaces/cli/main.py index d634060..f1a401e 100644 --- a/src/ad_seller/interfaces/cli/main.py +++ b/src/ad_seller/interfaces/cli/main.py @@ -337,4 +337,10 @@ def chat(): if __name__ == "__main__": - app() + import os + import sys + try: + app() + except SystemExit as e: + os._exit(e.code if isinstance(e.code, int) else 0) + os._exit(0) From 9ba96f09b4e7b6d12ff5f148be26838308c6f661 Mon Sep 17 00:00:00 2001 From: ATC964 <82515918+atc964@users.noreply.github.com> Date: Wed, 24 Jun 2026 13:13:38 -0400 Subject: [PATCH 2/2] Drop unused 'sys' import from CLI force-exit wrapper (ar-r82f.21 CI fix) Co-Authored-By: Claude Opus 4.7 (1M context) --- src/ad_seller/interfaces/cli/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ad_seller/interfaces/cli/main.py b/src/ad_seller/interfaces/cli/main.py index f1a401e..a49462a 100644 --- a/src/ad_seller/interfaces/cli/main.py +++ b/src/ad_seller/interfaces/cli/main.py @@ -338,7 +338,7 @@ def chat(): if __name__ == "__main__": import os - import sys + try: app() except SystemExit as e: