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_destroyed
for 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 debug
to see session cleanup messages. - Watch for “Extra unexpected referrers” and “Failed to release session” in logs.
- Test with
--num-procs 2
to 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_destroyed
hooks to free resources. - Use
session_context.locals
for session data isolation. - Monitor server memory via
psutil
or APM. - Containerize with strict memory limits and probes.