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..a49462a 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 + + try: + app() + except SystemExit as e: + os._exit(e.code if isinstance(e.code, int) else 0) + os._exit(0)