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.

Hi RSDancey,

thanks a lot for sharing this detailed information and your suggested solution and workaround.

I have created an internal ticket (erm47261) for our dev team to review the issue.

Greetings,

Margit

Hello Ryan,

since BlueSpice 5.2.1 (first public BlueSpice 5.2 version), the previous ping mechanism (regular call from client to server, getting notifications, online users, warning of other people editing the page etc.) is replaced by a websocket connection, where a wire container handel the connection. It is a fundamental mechanism that is included in all editions of BlueSpice, including the free edition.

If your installation uses bluespice-deploy, please upgrade to the latest tag 5.2.2 (or a tag matching your docker images) of the project, with which the new containers (wire, prepare, upgrade and so on) are well integrated. I host a free edition of 5.2.2 myself, the installation works smoothly.

If you indeed prefer a different way of running BlueSpice, quite some coding efforts would be need to ensure the compatibility between different modules - at least the official project should be used as a reference for vibe coding tools / agents.

In the internal ticket my colleague mentioned, I’ll try to add a bail out mechanism when the wire service is indeed not available.

Thank you for your participation in the community, and wish that your BlueSpice installation works smoothly soon.

Greetings,
Hua

I reverse engineered how my systems got into this state (tl;dr: working with a bluespice-deploy script older than 5.2.2). I’m updating my multiwiki installer to address this and I’m including a check in that installer that reviews the most current bluespice-deploy script to see if any new containers or services have been added and if one or more are detected my installer will abort and notify the user that the multiwiki installer project needs to be updated.

Thanks for disentangling this issue for me Hua.