Skip to content

fix(internal-plugin-mercury): improve handling of 4000 close code - #5065

Open
rarajes2 wants to merge 2 commits into
webex:nextfrom
rarajes2:mercury-4000-INC0056262
Open

fix(internal-plugin-mercury): improve handling of 4000 close code#5065
rarajes2 wants to merge 2 commits into
webex:nextfrom
rarajes2:mercury-4000-INC0056262

Conversation

@rarajes2

@rarajes2 rarajes2 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

COMPLETES #< SPARK-808019 >

This pull request addresses

Fixes the mercury close code 4000 handling for server rebalancing.

by making the following changes

  • Old connection gets 4000 (SDK connected twice): When a second connect replaces the socket in this.sockets, the map holds the new socket while the old socket still fires its close. So isActiveSocket is false → the old socket's listeners are cleaned up (by the existing top-level logic), offline.replaced is emitted, and no reconnect is triggered. The active connection stays alive.
  • Active socket gets 4000 directly from Mercury: sourceSocket === sessionSocketisActiveSocket is true → emits offline.transient and calls _reconnect(socketUrl, sessionId) to recover the connection.

Change Type

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Tooling change
  • Internal code refactor

The following scenarios were tested

  • mercury-events.js: changed the parametrized 4000 expectation from replace to reconnect (that test closes the active socket).
  • mercury.js: added a new #_onclose() with code 4000 (replaced connection) describe block with three cases — active socket reconnects, non-active (old) socket does not reconnect and stays connected, and old socket listeners are cleaned up.

Note: I ran build:src since the unit tests execute against dist/.

Vidcast: 4000 close code coming from the server (rebalancing case)
https://app.vidcast.io/share/f487df24-2e47-4cfd-9bb3-42d07e7fd7c3

Vidcast: Mercury 4000 close code testing for two times connect
https://app.vidcast.io/share/68fa87d8-2d4c-4125-b6e8-8cb6b18b8aa3

The GAI Coding Policy And Copyright Annotation Best Practices

  • GAI was not used (or, no additional notation is required)
  • Code was generated entirely by GAI
  • GAI was used to create a draft that was subsequently customized or modified
  • Coder created a draft manually that was non-substantively modified by GAI (e.g., refactoring was performed by GAI on manually written code)
  • Tool used for AI assistance (GitHub Copilot / Other - specify)
    • Github Copilot
    • Other - Cursor
  • This PR is related to
    • Feature
    • Defect fix
    • Tech Debt
    • Automation

I certified that

  • I have read and followed contributing guidelines
  • I discussed changes with code owners prior to submitting this pull request
  • I have not skipped any automated checks
  • All existing and new tests passed
  • I have updated the documentation accordingly

Make sure to have followed the contributing guidelines before submitting.

@rarajes2
rarajes2 requested review from a team as code owners July 2, 2026 07:26
@rarajes2 rarajes2 added the validated If the pull request is validated for automation. label Jul 2, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2764a46c07

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +916 to +919
this.logger.info(
`${this.namespace}: old socket ${sessionId} replaced; will not reconnect`
);
this._emit(sessionId, 'offline.replaced', event);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve active socket on old 4000 closes

When an old socket closes with 4000 after a newer socket has been stored for the same session, _onclose has already run this.sockets.delete(sessionId) before reaching this branch, so the map entry that gets removed is the newer active socket. This path then emits offline.replaced and skips reconnect while leaving this.sockets empty; later getSocket(), disconnectAll(), and the active socket's own close cannot find it, so the SDK can leak the live socket or fail to recover when it closes. Only delete the map entry for the active socket, or re-store the active socket before taking this branch.

Useful? React with 👍 / 👎.

Comment thread packages/@webex/internal-plugin-mercury/src/mercury.js

@mkesavan13 mkesavan13 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved for the code changes. Needs to be merged only after doing a cross testing with Mercury team in INT

@mkesavan13 mkesavan13 added validated If the pull request is validated for automation. and removed validated If the pull request is validated for automation. labels Jul 2, 2026
@github-actions github-actions Bot removed the validated If the pull request is validated for automation. label Jul 3, 2026
@Shreyas281299 Shreyas281299 added the validated If the pull request is validated for automation. label Jul 3, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e2cee02d2f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

`${this.namespace}: active socket ${sessionId} closed with 4000; reconnecting`
);
this._emit(sessionId, 'offline.transient', event);
this._reconnect(socketUrl, sessionId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid reconnecting on replacement closes

When a 4000 close is caused by another tab/process replacing this Mercury connection, this socket is still the active socket inside the current SDK instance because the replacement is not in this.sockets; socket-base.js also normalizes close reason replaced to code 4000. Reconnecting here makes the replaced client immediately create a new connection and can kick the newer client off (or loop) instead of surfacing offline.replaced. Please only reconnect when the 4000 can be distinguished as a rebalance/transient close, not for generic replacements.

Useful? React with 👍 / 👎.

this.logger.info(`${this.namespace}: socket ${sessionId} replaced; will not reconnect`);
if (isActiveSocket) this._emit(sessionId, 'offline.replaced', event);
// If not active, nothing to do
if (isActiveSocket) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't look right - we're changing the behavior for the isActiveSocket case. isActiveSocket is primarily for handling LLM where we can have multiple LLM connections, for Mercury we always have just one, so you would never have isActiveSocket==false for Mercury.
Also the testing done in the vidcast is not representative of the real world scenario, because it's setting up both mercury connections with same WDM in the same SDK instance. In real life it's 2 web apps running in separate windows, so 2 separate SDK instances each one has just a single Mercury connection.

@chrisadubois chrisadubois left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

validated If the pull request is validated for automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants