A bug-fix release for 1.2. There are no API, default or wire-format changes. Upgrading is recommended for long-running servers that use the in-memory state backend (#3080): session state was never expired while the process ran.
Fixed
- A LiveView page no longer logs "non-serializable value: FallbackStorage" (or
PermWrapper,WSGIRequest,AnonymousUser) on every render (#3061). The page-shell render (render_full_template) sent the context-processor values of the HTTP GET through the state normalizer, and the HTTP POST fallback hid its injected processor values from the #1786 filter. Both paths now drop non-serializable request-scoped values before normalizing, the same way the dj-root and WebSocket render already did. The values still reach the template, so{% for m in messages %}works inside and outside the LiveView root. A non-serializable attribute of the view itself still warns. 7 regression cases inpython/tests/test_full_template_context_processors_3061.py. - Presence could raise
AttributeError: partially initialized module 'djust.tenants.mixin'when two threads first used it together (#3079).
tenant_scoped_presence_keyreadTenantMixinstraight off the
sys.modulesentry, which is a half-built module while another thread is
still importing it (HTTP worker threads and the channels sync thread, for
example). It now takes the class with a normal import, which waits on the
module's import lock. Apps without tenants still never import the module.
3 regression cases intests/unit/test_presence_tenant_import_race_3079.py,
including a slow-import shim that holds the module half-imported while a
second thread asks for a presence key. - The in-memory state backend never expired anything, so memory grew with
every new session for the life of the process (#3080).SESSION_TTL
(default 3600 s) was applied only bydjust clearand
cleanup_expired_sessions(), which nothing called at runtime. Each entry
holds its view's full render state: about 270 KB of live heap per session in
a snake-arena load test, whereSESSION_TTL = 60still left 65, then 129,
193 and 257 entries across 64-client cycles. An entry not written for the
TTL is now a miss onget()and is dropped, andset()sweeps expired
entries at most once permin(SESSION_TTL, 60)seconds.SESSION_TTL = 0
still means never expire. The deployment guide now gives the per-session
cost and explains why RSS levels off rather than falls. 9 regression cases in
python/tests/test_memory_state_backend_ttl_3080.py. MemoryTrackerretriedimport psutilon every event. With psutil not
installed, each failed import re-scannedsys.path: about 42 µs per event
on the event-loop thread. Whether psutil is installed is now checked once, at
module import. 4 regression cases in
python/tests/test_memory_tracker_psutil_probe.py.
What's Changed
- fix: presence import race (#3079), in-memory state backend TTL (#3080), psutil probe [1.2 backport of #3083] by @johnrtipton in #3084
- fix: keep context-processor values out of the state normalizer (#3061) [backport of #3070 to 1.2] by @johnrtipton in #3086
Full Changelog: v1.2.1...v1.2.2