Skip to content

fix: stop aiohttp Socket Mode connect() retrying forever after close - #1956

Merged
WilliamBergamin merged 2 commits into
mainfrom
fix/aiohttp-socket-mode-connect-stops-when-closed
Sep 3, 2026
Merged

fix: stop aiohttp Socket Mode connect() retrying forever after close#1956
WilliamBergamin merged 2 commits into
mainfrom
fix/aiohttp-socket-mode-connect-stops-when-closed

Conversation

@WilliamBergamin

@WilliamBergamin WilliamBergamin commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

The aiohttp Socket Mode SocketModeClient.connect() looped with while True:, and its retry
handler never checked self.closed. If a connect/reconnect attempt was in flight when the client
was closed, every retry's ws_connect() raised RuntimeError: Session is closed, so the loop kept retrying at the ping_interval cadence forever.

The fix aligns connect() with the while not self.closed: idiom already used by its sibling loops (monitor_current_session, receive_messages, and the base process_messages), and returns from the retry handler once self.closed is set. A background task orphaned by shutdown now exits within one iteration instead of spinning forever; normal startup/reconnect is unchanged.

Closes #1913.

Testing

./scripts/run_tests.sh tests/slack_sdk_async/socket_mode/test_aiohttp.py

To watch it fail against the pre-fix code, restore the old connect() (keeping the new test), then
put the fix back:

git fetch origin
git checkout origin/main -- slack_sdk/socket_mode/aiohttp/__init__.py   # buggy `while True:` connect()
./scripts/run_tests.sh tests/slack_sdk_async/socket_mode/test_aiohttp.py
#  -> test_connect_returns_when_closed spins on the closed session;
#     asyncio.wait_for(..., timeout=1.0) raises TimeoutError -> FAIL

git checkout HEAD -- slack_sdk/socket_mode/aiohttp/__init__.py          # restore the fix
./scripts/run_tests.sh tests/slack_sdk_async/socket_mode/test_aiohttp.py   # PASS

(Equivalent manual repro: change while not self.closed: back to while True: and delete the
if self.closed: return guard in connect()'s except block.)

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.

…1913)

SocketModeClient.connect() used `while True` and its retry handler never
checked self.closed, so once close() closed the aiohttp ClientSession the
loop spun forever on `RuntimeError: Session is closed` (observed as 270k+
errors over 46 days in production). Make connect() respect self.closed like
its sibling loops (monitor_current_session, receive_messages) already do:
guard the loop with `while not self.closed` and return from the retry
handler once shutdown has begun.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
@WilliamBergamin WilliamBergamin added the bug M-T: A confirmed bug report. Issues are confirmed when the reproduction steps are documented label Sep 2, 2026
@WilliamBergamin WilliamBergamin changed the title fix: stop aiohttp Socket Mode connect() retrying forever after close (#1913) fix: stop aiohttp Socket Mode connect() retrying forever after close Sep 2, 2026
@WilliamBergamin WilliamBergamin self-assigned this Sep 2, 2026
@WilliamBergamin WilliamBergamin added this to the 3.45.0 milestone Sep 2, 2026
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.08%. Comparing base (9d1d6b9) to head (13bca88).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1956      +/-   ##
==========================================
+ Coverage   84.06%   84.08%   +0.01%     
==========================================
  Files         118      118              
  Lines       13505    13509       +4     
==========================================
+ Hits        11353    11359       +6     
+ Misses       2152     2150       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@WilliamBergamin
WilliamBergamin marked this pull request as ready for review September 2, 2026 17:31
@WilliamBergamin
WilliamBergamin requested a review from a team as a code owner September 2, 2026 17:31
Regression coverage for #1913: assert the aiohttp Socket Mode connect() retry handler returns without logging or retrying when an in-flight attempt raises after close(). The existing test only exercised the `while not self.closed` loop condition, not the except-block guard.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>

@zimeg zimeg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@WilliamBergamin LGTM! I have one comment on logging but it's a ramble.

Comment on lines +409 to +410
if self.logger.level <= logging.DEBUG:
self.logger.debug(f"Stopped connecting because the client is closed (error: {e})")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🪬 note: I'm surprised self.logger.debug doesn't check this condition itself but I think this log is quite useful.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This logic follows the existing pattern in the file, but I'm not sure why we have this condition, I need to take a deeper dive into it

@WilliamBergamin
WilliamBergamin merged commit 373cb17 into main Sep 3, 2026
18 checks passed
@WilliamBergamin
WilliamBergamin deleted the fix/aiohttp-socket-mode-connect-stops-when-closed branch September 3, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:async bug M-T: A confirmed bug report. Issues are confirmed when the reproduction steps are documented semver:patch socket-mode Version: 3x

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SocketModeClient (aiohttp backend): connect() retries forever against a closed ClientSession — orphaned retry loop survives close()

2 participants