Skip to content

Automatically pause circuit on inactivity #64886

@javiercn

Description

@javiercn

Extend Blazor's circuit pause/resume feature to opt-in to automatically pause circuits when we detect the user is not active. We do this when the browser tab is hidden for a configurable period (default: 2 minutes) and optionally pausing circuits on visible tabs when user inactivity is detected through browser events.

Motivation and goals

Current behavior: When users switch away from a Blazor Server app, the circuit remains active indefinitely as long as the SignalR connection stays alive. On desktop browsers, WebSocket connections can remain stable for hours or even days in hidden tabs, meaning circuits continue consuming server resources (CPU, memory) even though the user is not actively using the app. While .NET 10.0 automatically persists circuit state on ungraceful disconnect, this only occurs when the connection is actually lost—which may never happen for hidden tabs with stable network conditions.

This feature addresses the following needs:

  • Desktop browsers can keep hidden tab circuits alive indefinitely (hours or days), wasting server resources until the user closes the tab or network fails
  • High-traffic applications accumulate many idle circuits as users switch between tabs, limiting scalability and increasing hosting costs for cloud-hosted apps
  • Developers currently must write custom JavaScript to implement proactive pausing, reinventing a common pattern seen in Gmail, Slack, and other web apps
  • .NET 10.0's circuit state persistence infrastructure and existing Blazor.pause()/Blazor.resume() APIs make automatic pausing practical, but require manual implementation
  • A built-in, configurable solution would provide consistent behavior and developer convenience while freeing server resources in ~2 minutes instead of waiting indefinitely while the connection remains alive.

In scope

  1. Automatic pause/resume for hidden tabs with configurable delay (default: 2 minutes), automatic resume on visibility, and graceful handling of race conditions when users return during pause operations
  2. Simple opt-in configuration API with diagnostics/logging for monitoring pause/resume events

Secondary (extension):

  1. Visible tab inactivity detection with configurable timeout (default: 5 minutes) and customizable activity events (mousedown, keydown, touchstart, wheel, scroll)

Out of scope

  • Extensibility/customization: No server-side detection, user warnings, custom pause/resume hooks, or component-level opt-out (app-level only)
  • Granular control: No per-user configuration, cross-tab coordination, or pause prevention for specific components

Risks / unknowns

// TBD

Examples

Example 1: Basic opt-in (default 2-minute timeout)

wwwroot/app.js:

// Enable automatic pause after 2 minutes of tab being hidden
Blazor.start({
  circuit: {
    autoPause: {
      enabled: true,
    }
  }
});

Developer experience:

  • User opens Blazor app, uses it normally
  • User switches to another tab (email, documentation, etc.)
  • After 2 minutes, circuit automatically pauses
  • Server resources freed, state saved to client storage
  • User returns 10 minutes later
  • Circuit automatically resumes, state restored
  • User continues exactly where they left off

Example 2: Custom timeout configuration

wwwroot/app.js:

// Aggressive resource management with 30-second delay
Blazor.start({
  circuit: {
    autoPause: {
      enabled: true,
      hiddenDelay: 30000  // 30 seconds - aggressive
    }
  }
});

Developer experience:

  • High-traffic app wants aggressive resource management
  • Sets 30-second delay for hidden tabs
  • Users who quickly switch back (< 30s) don't experience pause/resume
  • Users who stay away longer have circuit paused faster

Example 3: Secondary feature - Visible tab inactivity detection

wwwroot/app.js:

// Enable both hidden tab and visible inactivity detection
Blazor.start({
  circuit: {
    autoPause: {
      enabled: true,
      hiddenDelay: 120000,  // 2 minutes for hidden tabs
      
      // Optional: Also pause on visible inactivity
      inactivity: {
        enabled: true,
        timeout: 300000,  // 5 minutes of no user interaction
        events: ['mousedown', 'keydown', 'touchstart', 'wheel', 'scroll']
      }
    }
  }
});

Developer experience:

  • User opens dashboard, reads data
  • User steps away without closing tab (gets coffee, meeting, etc.)
  • No interaction for 5 minutes
  • Circuit automatically pauses
  • User returns, moves mouse
  • Circuit resumes automatically
  • Dashboard updates with latest data

Metadata

Metadata

Assignees

Labels

area-blazorIncludes: Blazor, Razor Components

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions