Skip to content

fix(socket-mode): only release connect_operation_lock in send_message when acquired - #1963

Open
dylanpulver wants to merge 1 commit into
slackapi:mainfrom
dylanpulver:fix-send-message-connect-lock
Open

fix(socket-mode): only release connect_operation_lock in send_message when acquired#1963
dylanpulver wants to merge 1 commit into
slackapi:mainfrom
dylanpulver:fix-send-message-connect-lock

Conversation

@dylanpulver

Copy link
Copy Markdown

Summary

#1926 fixed if self.connect_operation_lock.locked() is True: release() in AsyncBaseSocketModeClient.connect_to_new_endpoint. The same shape is still in send_message() in both async backends.

websockets is the worse of the two: its retry block never acquires the lock, it only releases it in finally. So while a reconnect holds the lock, any send_message() that falls into the retry path releases the reconnect's lock, and a second reconnect can start while the first is still running. The aiohttp sibling does acquire here, which is what makes the omission visible.

aiohttp acquires but releases based on locked(), so a task cancelled while awaiting acquire() releases whichever task does hold the lock. That is the case #1926 describes.

Both now track whether this task acquired. The three sync paths (builtin, websocket_client, rtm_v2) take the lock with with and cannot get this wrong, so they needed no change.

Testing

A test per backend, in the style of the one added with #1926: another task holds the lock, send_message() hits its retry path and is cancelled, and the lock must still be held afterwards. Each fails on main and passes with the change.

  • pytest tests/slack_sdk_async/socket_mode/ — 22 passed (20 before these two)
  • ./scripts/lint.shruff format --check 455 files clean, ruff check slack/ slack_sdk/ clean
  • mypy --config-file pyproject.toml on both changed modules — no issues

I ran those individually rather than through ./scripts/run_validation.sh, so I have left that box unchecked.

Category

  • slack_sdk.web.WebClient (sync/async) (Web API client)
  • slack_sdk.webhook.WebhookClient (sync/async) (Incoming Webhook, response_url sender)
  • slack_sdk.socket_mode (Socket Mode client)
  • slack_sdk.signature (Request Signature Verifier)
  • slack_sdk.oauth (OAuth Flow Utilities)
  • slack_sdk.models (UI component builders)
  • slack_sdk.scim (SCIM API client)
  • slack_sdk.audit_logs (Audit Logs API client)
  • slack_sdk.rtm_v2 (RTM client)
  • /docs (Documents)
  • /tutorial (PythOnBoardingBot tutorial)
  • tests/integration_tests (Automated tests for this library)

Requirements

  • I've read and understood the Contributing Guidelines and have done my best effort to follow them.
  • I've read and agree to the Code of Conduct.
  • I've run python3 -m venv .venv && source .venv/bin/activate && ./scripts/run_validation.sh after making the changes.

… when acquired

slackapi#1926 fixed this in AsyncBaseSocketModeClient.connect_to_new_endpoint, but
the same `if self.connect_operation_lock.locked() is True: release()` shape
is still in send_message() in both async backends, and neither had a test.

websockets is the worse of the two: its retry block never acquires the lock
at all, it only releases it. So whenever a reconnect holds the lock and a
send_message() falls into the retry path, send_message() releases the
reconnect's lock and two reconnects can run at once. The aiohttp sibling
does acquire here, which is what makes the omission visible.

aiohttp acquires but releases on locked(), so a task cancelled while waiting
on acquire() releases whichever task does hold the lock. That is exactly the
case slackapi#1926 describes.

Both now track whether this task acquired, matching slackapi#1926 and the sync
backends, which take the lock with `with` and cannot get this wrong.
@dylanpulver
dylanpulver requested a review from a team as a code owner September 9, 2026 11:27
@salesforce-cla

salesforce-cla Bot commented Sep 9, 2026

Copy link
Copy Markdown

Thanks for the contribution! Before we can merge this, we need @dylanpulver to sign the Salesforce Inc. Contributor License Agreement.

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.

1 participant