Repository navigation
Conversation
A hosting platform can now give every worker and pod the same signing secret (DASH_SECRET_KEY) and pick the shared-storage backend (DASH_SHARED_STORAGE) without editing the app. Without a shared secret, multi-worker stream requests 403 silently; the first failure in each process now logs a warning.
Dash performance benchmarks✅ all within thresholds
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: 0.99x - divided out of the baseline ratios so they compare like for like (the absolute warn/fail ceilings are left un-scaled); calibrated on |
camdecoster
left a comment
There was a problem hiding this comment.
Approved. I made a few small comments, but nothing blocking. Is the docs update for the env vars on Jessica's radar?
Could you please address the merge conflicts?
| scheme = urlparse(raw).scheme.lower() | ||
| if scheme in ("redis", "rediss"): | ||
| _require_redis() | ||
| return functools.partial(RedisSharedStorage, url=raw) |
There was a problem hiding this comment.
Should users be able to set the redis key prefix when using the env var? I don't think they'll be able to with the current implementation.
There was a problem hiding this comment.
Added a key_prefix query param on the Redis URL, e.g. redis://host:6379/0?key_prefix=myapp. It's stripped before the URL goes to redis-py, other query params pass through.
| def _redact(value: str) -> str: | ||
| # Keep credentials in a URL out of the error message. | ||
| return re.sub(r"(://)[^/@]*@", r"\1***@", value) |
There was a problem hiding this comment.
This regex pattern can still leak secrets. Try running the following through:
valkey://default:Zx9/Qm+4kP@cache.internal:6379/0
I'd recommend just removing this function and skipping including a redacted secret. A description of the error should be enough to point users in the right direction.
There was a problem hiding this comment.
Good catch, removed _redact. Errors no longer include the value at all, just the reason. Added your URL to the test.
| _require_redis() | ||
| return functools.partial(RedisSharedStorage, url=raw) | ||
| if scheme == "diskcache": | ||
| parsed = urlparse(raw) |
There was a problem hiding this comment.
This won't parse % codes in URLs as is (though maybe that's rare?).
There was a problem hiding this comment.
Fixed, the diskcache path is now unquoted. Redis URLs were already fine since redis-py decodes user/password itself; added tests for both.
|



Streaming callbacks (#3931) and shared storage (#3930) break once an app runs on several workers or pods, and a hosting platform (Plotly Cloud, Dash Enterprise, self-hosted) can't fix that without editing app code. This adds two env vars, following the existing
DASH_*convention, and a warning for the failure that is silent today.Changes
DASH_SECRET_KEY: the signing secret is now looked up asserver.secret_key>DASH_SECRET_KEY> secret saved in the background-callback store > random per process. Used for Dash's own signing only and never copied ontoserver.secret_key, so Flask sessions are untouched. An empty value counts as unset.-w 4and nosecret_key, most downlink polls return 403 (25 of 40 measured).DASH_SHARED_STORAGE: picks the backend when the app doesn't passshared_storage=:local,none,diskcache:///abs/path, or aredis:///rediss://URL.shared_storagenow has a sentinel default, so an explicit argument,Noneincluded, always wins.app.shared_storageis first read.dash[redis]/dash[diskcache]raises the sameImportErroras the explicit path, atDash()construction.cluster://is reserved and raises "not supported in this version". Anything else raisesInvalidConfignaming the variable and value, with URL credentials replaced by***.server.secret_key/DASH_SECRET_KEY. Still 403. A request with no token is not logged.No behavior change for apps that set neither variable.
Tests
ImportErrortext, credential redaction, warning fires once.tests/streaming/test_stream_wsgi.py: gunicorn-w 4.DASH_SECRET_KEY: every poll is 200 and a stream completes in the browser. Fails before this change.dash_duotest selecting Redis throughDASH_SHARED_STORAGE. Skips without Redis, like the other Redis tests.