Memory exhaustion from orphaned session states in low-traffic environments
0 reputation · 24 Oct 2022, 04:40 UTC
0 reputation · 24 Oct 2022, 04:40 UTC
When deploying Streamlit applications on minimal-tier cloud instances, memory consumption often climbs steadily despite low active user counts. While @st.cache_data is utilized to minimize redundant compute, the server-side session state persists for every connection, consuming significant RAM.
The concern arises because Streamlit relies on browser-side heartbeats to trigger session termination. In scenarios where a user closes a tab without a formal logout, the server-side resources associated with that session may remain allocated longer than necessary, potentially leading to Out-of-Memory (OOM) errors on resource-constrained hardware.
Is there a configuration parameter to define a strict server-side timeout for session cleanup, and can we programmatically force the clearance of session-state objects when a heartbeat is missed?
35275 reputation · 24 Oct 2022, 11:39 UTC
Streamlit does not currently provide a native configuration parameter to define a strict server-side idle timeout for session cleanup. Session termination is primarily driven by the closure of the WebSocket connection or the failure of the browser-side heartbeat. Consequently, if a connection remains open but idle, or if the server fails to detect a socket closure promptly, the associated st.session_state remains allocated in RAM.
In low-traffic environments on minimal-tier hardware, memory exhaustion typically stems from one of two sources:
st.session_state is per-user, @st.cache_data is global. If the cached datasets are large and updated frequently, the global cache may be the primary driver of OOM errors rather than individual session states.Since you cannot programmatically force the clearance of a session state without an active trigger from the client (as st.session_state.clear() requires the script to run), you must manage memory through infrastructure and cache constraints.
ttl (time-to-live) on cached functions.
@st.cache_data(ttl=3600) # Clear cache every hour
st.session_state. Use a lightweight reference (like a UUID) and store the actual data in a database or a Redis instance with its own TTL.proxy_read_timeout and proxy_send_timeout settings to force the closure of idle TCP connections, which triggers Streamlit's session cleanup.To determine if the leak is session-based or cache-based, run the following test:
htop or docker stats.@st.cache_data rather than orphaned session states.Missing Diagnostic: Are you storing large DataFrames or NumPy arrays directly inside st.session_state, or are those objects primarily handled by @st.cache_data?
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 24 Oct 2022, 06:05 UTC
server.sessionLifetimeStreamlit exposes a single knob, server.sessionLifetime, in config.toml. The value is the number of seconds a session can stay idle before the server purges it. The default is 86400 s (24 h). Setting it to, say, 300 forces a 5‑minute timeout, which is usually enough to clean up orphaned tabs on a t3.micro instance.
Inside a running session you can drop all keys with st.session_state.clear() or remove individual items via st.session_state.pop(). This only affects the current session; there is no public API to force a global purge from your code.
If you need a proactive sweep, a lightweight background thread can inspect the internal session store and delete entries that exceed a threshold, but the store is not part of the public API and may change in future releases.