Effective server-side memory management is crucial for stable, scalable Bokeh applications in production. This guide covers configuration options, custom cleanup hooks, and containerization strategies to ensure Bokeh servers gracefully release memory and avoid leaks when serving multiple users.
1. Configure Session Timeouts and Cleanup Intervals
Bokeh provides built-in CLI options to limit unused session lifetimes and trigger periodic cleanup:
| Option | Description | Example |
|---|---|---|
--unused-session-lifetime |
Maximum time (ms) an idle session is kept before cleanup | --unused-session-lifetime 300000 (5 minutes) |
--check-unused-sessions |
Interval (ms) between cleanup checks | --check-unused-sessions 60000 (1 minute) |
2. Use Custom Session Destruction Hooks
Register Python callbacks that run when a session is destroyed to explicitly release resources—close database connections, clear caches, or delete large objects.
from bokeh.io import curdoc def cleanup_resources(session_context): # Example: close DB connection, clear caches db_conn = session_context.locals.get('db_conn') if db_conn: db_conn.close() cache = session_context.locals.get('data_cache') if cache: cache.clear() # Register the hook on the current Document curdoc().on_session_destroyed(cleanup_resources)
“Bokeh now supports
Document.on_session_destroyedfor per-session cleanup logic, enabling developers to override default GC behavior.”
3. Leverage session_context for Per-Session Data
Avoid global variables for session-specific data. Use session_context.locals to store per-session objects that Bokeh will release automatically upon cleanup.
def modify_doc(doc):
# Store large DataFrame in session_context, not module global
df = load_large_dataframe()
doc.session_context.locals['data_cache'] = df
p = figure()
p.line(df.x, df.y)
doc.add_root(p)
# In application startup:
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
handler = FunctionHandler(modify_doc)
app = Application(handler)
4. Monitor Memory Usage in Production
Continuously monitor Bokeh server processes with psutil or external APM tools to detect unbounded memory growth.
# monitor_memory.py
import psutil, time
def monitor_bokeh_server(name_filter='bokeh'):
while True:
for proc in psutil.process_iter(['name','pid','memory_info']):
if name_filter in proc.info['name']:
rss_mb = proc.info['memory_info'].rss / (1024*1024)
print(f"{proc.info['pid']}: {rss_mb:.1f} MB")
time.sleep(60)
5. Containerization and Resource Limits
Deploy Bokeh servers in Docker or Kubernetes with strict memory limits to enforce OOM (Out Of Memory) safety:
# Dockerfile snippet
FROM python:3.11-slim
RUN pip install bokeh panel
COPY . /app
CMD ["bokeh", "serve", "/app", "--allow-websocket-origin=*", \
"--unused-session-lifetime", "300000", \
"--check-unused-sessions", "60000"]
In Kubernetes, set resources.limits.memory and resources.requests.memory to desired values and configure liveness/readiness probes to restart pods on OOM failures.
6. Advanced: Dynamic Cleanup via Tornado Lifecycle
For deep customization, tap into Tornado web server hooks to perform cleanup at HTTP connection close:
from bokeh.server.tornado import BokehTornado
class CustomTornado(BokehTornado):
def on_connection_close(self, handler):
# Perform session-specific cleanup
session_context = handler.get_session_context()
cleanup_resources(session_context)
super().on_connection_close(handler)
# Use CustomTornado when starting server programmatically
from bokeh.server.server import Server
server = Server(applications={'/': app}, tornado_application=CustomTornado)
server.start()
7. Troubleshooting and Diagnostics
- Enable debug logging:
bokeh serve app.py --log-level debugto see session cleanup messages. - Watch for “Extra unexpected referrers” and “Failed to release session” in logs.
- Test with
--num-procs 2to isolate per-process memory behavior.
Quick Reference
| Feature | Configuration | Purpose |
|---|---|---|
| unused-session-lifetime | CLI flag | Automatically cleanup idle sessions after timeout |
| check-unused-sessions | CLI flag | Periodic session cleanup interval |
| on_session_destroyed | Document hook | Custom resource cleanup logic |
| session_context.locals | API | Store per-session data safely |
| Container resource limits | Docker/K8s config | Enforce memory caps, trigger restarts |
Production Checklist
- Enable
--unused-session-lifetime&--check-unused-sessions. - Register
on_session_destroyedhooks to free resources. - Use
session_context.localsfor session data isolation. - Monitor server memory via
psutilor APM. - Containerize with strict memory limits and probes.
