Skip to content

Require shared storage for HTTP streaming callbacks - #4099

Merged
T4rk1n merged 2 commits into
devfrom
stream-requires-shared-storage
Oct 29, 2026
Merged

T4rk1n merged 2 commits into
devfrom
stream-requires-shared-storage

Conversation

@T4rk1n

@T4rk1n T4rk1n commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #4095. With shared storage off, a streaming callback over HTTP fell back to one connection per stream. That works on a laptop, then breaks once deployed (browsers cap connections per host), so it gave false confidence. Now it fails loudly, the same way locally and when deployed.

Changes

  • _setup_server raises StreamCallbackError when the app has streaming callbacks that run over HTTP and no shared storage. The message names the callbacks and how to fix it: shared_storage=, DASH_SHARED_STORAGE, or WebSocket. It runs next to the background-callback validation, so every request fails with the same error until it's fixed.
  • WebSocket streaming callbacks (websocket_callbacks=True or websocket=True) are exempt only on a backend that serves WebSockets (FastAPI, Quart). On Flask those flags still mean HTTP, so the check applies.
  • Docs (Dash docstring, .ai/ARCHITECTURE.md) no longer describe the fallback. The doc notes that browsers without SharedWorker still stream WebSocket-app callbacks over HTTP; the server can't detect that.

Tests

  • stcb025/026: raises at setup and on every request.
  • stcb027: FastAPI WebSocket streams (app-level and per-callback) need no shared storage.
  • stcb029: the same flags on Flask still raise.
  • stcb028: shared storage enabled sets up fine.
  • tests/streaming/conftest.py sets DASH_SHARED_STORAGE=local, so streaming tests run with shared storage unless they pass their own.

An app with a streaming callback that runs over HTTP and no shared
storage now fails at server setup with StreamCallbackError, instead of
falling back to one connection per stream: that fallback works locally
but breaks once deployed. Streaming callbacks over WebSocket on a backend
that supports it (FastAPI, Quart) do not need shared storage.
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Dash performance benchmarks

✅ all within thresholds

scenario metric p90 (ms) median growth baseline p90 note
✅ callback_chain chain_ms 433.9 419.8 0.93x 499.1
✅ callback_chain graph_ms 2.9 2.9 1.0x 2.4
✅ callback_fanout fanout_ms 82.3 79.8 0.92x 92.5
✅ deep_nesting render_ms 56.4 54.8 1.18x 56.8
✅ full_children_replace replace_ms 5505.3 1975.9 18.39x 4697.1
✅ initial_render_large render_ms 631.4 590.8 1.06x 694.4
✅ initial_render_small render_ms 119.9 98.7 0.93x 104.0
✅ patch_append_nested append_ms 126.7 96.4 2.22x 192.3
✅ patch_append_toplevel append_ms 117.2 88.5 2.14x 140.2
✅ patch_scalar_update_large update_ms 144.7 134.1 0.91x 202.9
✅ wildcard_all_resolve wildcard_ms 310.6 298.2 0.93x 313.6
✅ wildcard_all_resolve graph_ms 1.3 1.3 1.0x 1.3

growth = late-third / early-third per-op time; ~1 is flat, a large value means the per-op cost scales with accumulated state.

machine scale vs baseline: 1.03x - divided out of the baseline ratios so they compare like for like (the absolute warn/fail ceilings are left un-scaled); calibrated on initial_render_small.

@sonarqubecloud

Copy link
Copy Markdown

@T4rk1n
T4rk1n merged commit 3bc84a4 into dev Oct 29, 2026
39 of 40 checks passed
@T4rk1n
T4rk1n deleted the stream-requires-shared-storage branch October 29, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants