Skip to content

Per-session dashboard services (alternative to #673)#688

Draft
SimonHeybrock wants to merge 3 commits intomainfrom
per-session-dashboard
Draft

Per-session dashboard services (alternative to #673)#688
SimonHeybrock wants to merge 3 commits intomainfrom
per-session-dashboard

Conversation

@SimonHeybrock
Copy link
Member

@SimonHeybrock SimonHeybrock commented Feb 6, 2026

Summary

Alternative approach to multi-session support, addressing the issues found in #673 during stress testing. This is not complete, but a basis for more exploration and discussion.

Instead of sharing Kafka consumers and adding complex session-aware layers (SessionRegistry, PlotDataService, etc.), this PR takes a simpler approach: each browser session gets its own independent Kafka consumer and service stack.

Closes #609.
Closes #672.

Approach

  • DashboardServices creation moved from app initialization to create_layout() (called per-session)
  • Each session has its own Kafka consumer/producer, eliminating resource sharing issues
  • Session cleanup via pn.state.on_session_destroyed() + browser heartbeat detection
  • Added --num-procs CLI argument for multiprocess mode (further isolation if needed)

Trade-offs vs #673

Aspect #673 (shared) This PR (per-session)
Kafka connections 1 per dashboard instance 1 per browser session
Memory Shared caches Duplicate caches per session
Complexity High (session routing, state machines) Lower (sessions are independent)
Failure isolation Sessions can interfere Sessions are isolated

Given our expected ~5 concurrent sessions and low data rates (MByte/s), the additional Kafka connections and memory are acceptable.

Known limitations

This is still brittle and a starting point for discussion:

  • Sessions may be incorrectly cleaned up when:
    • Switching to another desktop/workspace
    • Browser tab goes to background for extended periods
    • Network interruptions
  • The browser heartbeat mechanism (ReactiveHTML counter) is a workaround for Panel's unreliable on_session_destroyed
  • The 20-second heartbeat timeout is a guess - may need tuning
  • Relies on Panels unpredictable mechanism of assigning session to processors. Would probably need to use a real load-balancer instead.

On top of this, we would also need to ensure that things like stored config is protected from being corrupted by multiple processes (and come up with a sync mechanism).

Changes

Core per-session architecture:

  • dashboard.py: Services created in create_layout(), cleanup registered via on_session_destroyed
  • dashboard_services.py: Added session heartbeats and browser liveness detection
  • reduction.py: Updated to pass services to abstract methods, added --num-procs

Heartbeat mechanism:

  • heartbeat_widget.py: ReactiveHTML widget that increments a counter from browser JS
  • kafka_transport.py: Added status sink for session heartbeats
  • Session publishes heartbeats to Kafka (visible in System Status tab)

Test plan

  • All 853 dashboard tests pass
  • Manual: Open multiple browser tabs, verify independent operation
  • Manual: Close tabs, verify cleanup logs appear
  • Manual: Test with --num-procs 3 for multiprocess mode
  • Stress test with rapid tab open/close cycles

🤖 Generated with Claude Code

SimonHeybrock and others added 3 commits February 6, 2026 11:15
Move DashboardServices creation from app initialization to per-session
creation in create_layout(). This allows each browser session to have
its own Kafka consumer/producer, avoiding the performance issues we
experienced with Panel's threaded mode when sharing resources across
multiple sessions.

Changes:
- DashboardBase.__init__ now only stores configuration
- Added _create_session_services() to create per-session services
- create_sidebar_content() and create_main_content() now receive
  services as a parameter instead of accessing self._services
- Session cleanup registered via pn.state.on_session_destroyed()
- Added --num-procs CLI argument to enable multiprocess mode
- Exposed exit_stack on DashboardServices for LogProducerWidget

Prompt: Help me brainstorm a bit: We are experiencing performance issues
using Panel's threaded mode when we have more than a couple of sessions.
We are thus considering to switch to multiple processes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Dashboard sessions now publish heartbeats like backend workers, making them
visible in the renamed "System Status" tab (previously "Backend Status").

Each session publishes a ServiceStatus with namespace="dashboard" every 2
seconds, allowing users to see all active dashboard sessions alongside
backend workers. Sessions send a final "stopping" heartbeat on cleanup.

Changes:
- Add status_sink to DashboardResources and transports
- Add session heartbeat logic to DashboardServices (UUID, started_at,
  rate-limited publish_heartbeat method)
- Call publish_heartbeat from the periodic step callback
- Rename "Backend Status" tab to "System Status"

Prompt: Have a look at the latest commit, we are trialing running the
dashboard in processes. It would be useful if the session would publish a
heartbeat, like the backend workers do, then we should see all active
sessions in the "Backend Status" tab (probably needs renaming then).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a browser tab closes, Panel's on_session_destroyed callback sometimes
fails to fire, leaving stale sessions with open Kafka connections. This adds
a browser-side JavaScript heartbeat to detect disconnected browsers and
trigger cleanup proactively.

The HeartbeatWidget uses ReactiveHTML to run JavaScript that increments a
counter every 5 seconds. Python checks if the counter has changed; if it
stops changing for 20 seconds, the browser is considered disconnected and
full session cleanup is triggered (same as on_session_destroyed would do).

Prompt: Session cleanup works sometimes, but misses stale sessions sometimes.
Please help me to port a solution we have in another branch - the
heartbeat-widget solution with browser-side javascript.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate notifications with multiple sessions and stale sessions Multi-session support for plots

1 participant