Skip to content

fix(socket-mode): reconnect immediately on Slack disconnect refresh - #2785

Open
hippi345 wants to merge 3 commits into
slackapi:mainfrom
hippi345:fix/2767-socket-mode-refresh-gap
Open

hippi345 wants to merge 3 commits into
slackapi:mainfrom
hippi345:fix/2767-socket-mode-refresh-gap

Conversation

@hippi345

@hippi345 hippi345 commented Oct 17, 2026 •

Copy link
Copy Markdown

Summary

When Slack sends {"type":"disconnect"} (including refresh_requested), @slack/socket-mode used to close the current WebSocket before opening a replacement and then treat the close as a reconnection failure. That left apps without a connection for several seconds.

This change handles a Slack-requested disconnect in SocketModeClient by opening the next connection immediately and keeping the old socket until the new one receives hello. A successful refresh is not counted as a consecutive failure.

If the replacement never becomes ready, the client does not stay stuck: a close on the new socket before hello, a close on the old socket while the refresh is still pending, or a hello timeout (clientPingTimeout) aborts the in-flight start(), closes leftover sockets, and recovers through delayReconnectAttempt so real failures still back off.

Until the replacement has received hello, acks are written on the old socket even if the new WebSocket is already OPEN. The remaining limitation is acks already in flight at the moment of switchover (when hello arrives and the old socket is closed).

Fixes #2767.

Changes

  • On a Slack type: disconnect message with auto-reconnect enabled, call start() right away instead of websocket.disconnect().
  • Keep the previous SlackWebSocket until the replacement handshake completes, then close it.
  • If the new socket fails before hello, the old socket dies during the refresh, or hello does not arrive in time: clear the refresh flag, emit disconnected so start() settles, close leftover sockets, and schedule delayReconnectAttempt.
  • Increment a connection-attempt id when aborting so a late apps.connections.open cannot attach a socket after recovery has already started.
  • While refreshInProgress is true and the old socket is still open, send() / acks use the old socket. The client switches to the new socket only after hello. The only remaining limitation is acks in flight at the moment of that switchover.
  • disconnect() during a refresh emits disconnected once.
  • If auto-reconnect is disabled, still close the current socket immediately (previous behavior).
  • Unexpected drops still use the existing delayReconnectAttempt path.

Testing

  • Unit test should acknowledge on the old socket while the new socket is OPEN but has not received hello fails on e4958bb (acks followed isActive() / WebSocket OPEN) and passes after this change.
  • Also covered: successful overlap refresh, replacement/close recovery, acks while connecting, a single disconnected if disconnect() runs mid-refresh, auto-reconnect disabled.
  • npm test --workspace=packages/socket-mode (unit + integration) on Node 22
  • npm run lint

Requirements

This change was prepared with AI assistance and reviewed by the author.

Open the next Socket Mode connection before closing the old one when
Slack sends type: disconnect, and skip the consecutive-failure delay.

Fixes slackapi#2767
@changeset-bot

changeset-bot Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4bd3f96

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@slack/socket-mode Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Abort an in-flight Slack-requested refresh if the new socket closes
before hello, the old socket dies while connecting, or hello times out,
then reconnect with the usual backoff. Route acks to the retiring
socket while the replacement is still connecting.
During a Slack-requested refresh the replacement WebSocket can be OPEN
before hello. Send acks on the retiring socket until the handshake
completes, and emit disconnected only once if disconnect() runs mid-refresh.
@hippi345
hippi345 marked this pull request as ready for review October 17, 2026 02:16
@hippi345
hippi345 requested a review from a team as a code owner October 17, 2026 02:16

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

socket-mode: Slack's disconnect (refresh_requested) leaves the app without a connection for 9–12 s

1 participant