You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
WebSocket callback concurrency is bounded by an unconfigurable thread pool #3825
WS callbacks are dispatched to a ThreadPoolExecutor sized min(32, cpu_count+4) (base_server.py:194-209). Digging into performance implications, this can pose issues because it means WS callback scaling is:
Not configurable. Both call sites (_fastapi.py:735, _quart.py:563) invoke get_callback_executor() with no max_workers, and no constructor param exposes it. Hitting the ~20-connection cap leaves "deploy more workers" as the only escape.
Async callbacks run one-per-thread.ws.py:435 calls asyncio.run() inside the worker thread, spinning a fresh event loop per callback. A persistent=True callback holds its thread (~8 MB stack) for the whole session while mostly await-ing
Users need to brute force scaling by adding more, and more, and more CPU cores, when one CPU core could handle many more threads than are currently allocated.
Proposed changes (independent):
Quick win: expose websocket_max_workers on the Dash constructor, threaded to the two call sites via getattr(dash_app, "_websocket_max_workers", None). ~5 lines, backward-compatible (None = current default). Lets users raise the cap past 32. This would scale memory linearly — 1000 threads ≈ 8 GB stacks.
Durable fix: route inspect.iscoroutine results onto the backend's existing event loop as tasks; keep the thread pool only for sync callbacks. Takes async-callback concurrency from "threads × 8 MB" to "coroutines × KB."
changed the title [-]WebSocket callback concurrency is bounded by an unconfigurable thread pool; async callbacks run one-per-thread[/-][+]WebSocket callback concurrency is bounded by an unconfigurable thread pool[/+]on Jun 17, 2026
Activity
[-]WebSocket callback concurrency is bounded by an unconfigurable thread pool; async callbacks run one-per-thread[/-][+]WebSocket callback concurrency is bounded by an unconfigurable thread pool[/+]