Skip to content

Add pooled option to ReqraftWebSocket for isolated connections #49

@Foxhoundn

Description

@Foxhoundn

Problem

ReqraftWebSocket pools connections by the url option via ReqraftWebSocketsManager.connections. This means multiple instances connecting to the same endpoint (e.g. 'lsp') always share the underlying WebSocket.

In qorus-ide, we have two independent consumers that both connect to /lsp:

  1. useLanguageServer hook — feeds the raw socket to Monaco's MonacoLspClient (which takes over onmessage)
  2. DpqlLspClient class — manages its own JSON-RPC request/response lifecycle over the same /lsp endpoint

These two cannot share a WebSocket because they have completely different message handling. Currently DpqlLspClient is forced to use a raw WebSocket with manual URL construction and heartbeat, duplicating what ReqraftWebSocket already provides.

Proposed Solution

Add an optional pooled flag to IReqraftWebSocketConfig (default: true for backward compatibility):

export interface IReqraftWebSocketConfig {
  url: string;
  pooled?: boolean; // default: true
  // ... existing options
}

When pooled: false, the instance should get its own isolated WebSocket connection instead of sharing one from the pool. The simplest implementation: use a unique internal pool key (e.g. url::nanoid()) so the existing pool machinery works unchanged, while getSocketUrl() still uses this.options.url for the actual WebSocket URL.

Implementation sketch

// In the constructor:
this._poolKey = this.options.pooled === false
  ? `${this.options.url}::${nanoid()}`
  : this.options.url;

// Then replace all pool-related `this.options.url` references with `this._poolKey`,
// except in `getSocketUrl()` which builds the actual WebSocket URL.

Affected pool references in ReqraftWebSocket:

  • connect() — pool lookup, store, increment
  • addHandler() / removeHandler() — delegates to ReqraftWebSocketsManager
  • remove() — pool check, decrement, close
  • startHeartbeat() / stopHeartbeat() — pool heartbeat timer

getSocketUrl() stays unchanged (uses this.options.url for the real URL path).

Usage

// Pooled (default, existing behavior — shared connection)
const shared = new ReqraftWebSocket({ url: 'lsp' });

// Isolated (own connection, same endpoint)
const isolated = new ReqraftWebSocket({ url: 'lsp', pooled: false });

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions