from __future__ import annotations import os from concurrent.futures import ThreadPoolExecutor # Shared executor for CPU-bound analytics (pandas/sklearn) and sync MSSQL I/O # (pyodbc is inherently synchronous and blocks the event loop if called directly). # # Workers are capped at 8 to avoid overwhelming the MSSQL connection pools. # In K8s: set ANALYTICS_WORKERS to match the pod's CPU limit. _WORKERS = min(8, int(os.environ.get("ANALYTICS_WORKERS", "0")) or (os.cpu_count() or 2) * 2) _executor: ThreadPoolExecutor | None = None def get_executor() -> ThreadPoolExecutor: global _executor if _executor is None: _executor = ThreadPoolExecutor(max_workers=_WORKERS, thread_name_prefix="analytics") return _executor def shutdown_executor() -> None: global _executor if _executor is not None: _executor.shutdown(wait=False) _executor = None