Websockets and Heavy Resource Load

Describe the issue / Steps to reproduce:
Page saving on one of the wikis I administer was taking 10+ seconds. On investigation I found that the server hosting that wiki was resource constrained due to the number of worker processes that it had spawned.

Several users had apparently set up tools to monitor pages on this wiki and they were scraping the page at a high frequency. The system was not able to naturally retire worker processes as a result.

Root Cause

In /app/conf/LocalSettings.php (baked into the container image), the following line is unconditional:

$GLOBALS[‘mwsgWireServiceWebsocketUrl’] = $GLOBALS[‘wgServer’] . ‘/_wire’;

This sets the wire WebSocket URL to https:///_wire regardless of whether the optional bluespice/wire service is deployed.

The client-side JavaScript (mwstake/mediawiki-component-wire/resources/bootstrap.js) attempts to open a WebSocket connection to this URL. Since no wire service exists, the connection fails. The onclose handler fires after 5 seconds, then _reconnect() schedules a retry after 1 second. This creates a permanent loop per open browser tab:

  1. GET /w/rest.php/mws/v1/user-token/generate — token generation (~every 3s)
  2. GET /_wire?token=… — WebSocket upgrade attempt that fails (nginx handles it as a normal HTTP request, returns ~12KB HTML page)

Each request spawns a php-fpm worker. With multiple users and multiple open tabs, this sustained load consumes significant CPU and PHP-FPM capacity, starving legitimate requests like page saves.

By contrast, mwsgWireServiceUrl (the server-side HTTP URL) is correctly gated on environment variables (WIRE_PROTOCOL, WIRE_HOST, WIRE_PORT) and resolves to an empty/broken value when the wire service is not configured, which effectively disables it. The WebSocket URL does not have equivalent protection.

Expected Behavior

mwsgWireServiceWebsocketUrl should only be set when the wire service is actually deployed — i.e., when the WIRE_HOST environment variable is configured. It should default to an empty string otherwise, which causes the client JS to skip the WebSocket connection entirely (the JS already guards against an empty URL: if (!mws.wire._url) { return null; }).

Suggested Fix

// In /app/conf/LocalSettings.php:
$GLOBALS[‘mwsgWireServiceWebsocketUrl’] = !empty(getenv(‘WIRE_HOST’))
? $GLOBALS[‘wgServer’] . ‘/_wire’
: ‘’;

Workaround

Add the following to post-init-settings.php for each wiki not running the wire service:

$GLOBALS[‘mwsgWireServiceWebsocketUrl’] = ‘’;

This is reproducible on any BlueSpice 5.2.x Docker deployment that does not include the bluespice/wire service container.

======

After implementing the Workaround in my BlueSpice Free installations the problem was resolved.