Skip to content

fix: re-subscribe rooms stream after forced socket reopen#7362

Merged
diegolmello merged 1 commit into
developfrom
rooms-freeze-android
Jun 1, 2026
Merged

fix: re-subscribe rooms stream after forced socket reopen#7362
diegolmello merged 1 commit into
developfrom
rooms-freeze-android

Conversation

@diegolmello

@diegolmello diegolmello commented May 29, 2026

Copy link
Copy Markdown
Member

Proposed changes

After the app sits in the background for a while the DDP socket goes stale, so foregrounding triggers checkAndReopenforceReopen. forceReopen drops every SDK subscription and reopens the socket without going through connect(), so the module-level roomsSubscription guard in subscribeRooms stays set. The next subscribeRooms() therefore short-circuits and never re-subscribes stream-notify-user, and the rooms list silently stops reflecting subscription/favorite/read changes until a manual reconnect or app restart.

This resets that guard from the socket 'close' listener (via unsubscribeRooms()) — the same teardown connect() already performs at startup — so the resume-login that follows the reopen re-subscribes stream-notify-user. stream-notify-user is the only stream behind that guard; the other streams (permissions, presence, settings, roles) call sdk.subscribe(...) unconditionally and were never affected.

Issue(s)

https://rocketchat.atlassian.net/browse/SUP-1047

How to test or reproduce

  1. Log in and open the rooms list.
  2. Background the app and cut connectivity (airplane mode) for ~60s so the DDP socket goes stale.
  3. Restore connectivity and foreground the app.
  4. From another client (or REST), trigger a subscriptions-changed event — e.g. favorite/unfavorite a room or mark one read.
  • Before: the rooms list does not update; the change only appears after a manual reconnect / app restart.
  • After: the rooms list updates in real time again.

Verified on an Android 16 emulator: after foregrounding, subscribeRooms() re-subscribes stream-notify-user and a favorite toggle then fires the handler and the WatermelonDB write. A regression test in connect.test.ts asserts the 'close' listener calls unsubscribeRooms() (and fails if the call is removed).

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

The fix lives in the 'close' listener rather than in subscribeRooms itself because 'close' is already the place app state is reset for reconnect (it dispatches disconnectAction() to flip Redux meteor.connected → false). The SDK's forceReopen documents this contract: it emits 'close' so connect.ts flips that state, otherwise the next 'connected' short-circuits and the loginRequest → subscribeNotifyUser chain never re-runs. The roomsSubscription guard is just a second piece of "am I subscribed?" state that has to be reset in that same spot.

Summary by CodeRabbit

  • Bug Fixes

    • Improved connection recovery so subscriptions are properly reset when VoIP/SDK connections close and reopen, ensuring notifications and real-time updates are re-established after reconnects.
  • Tests

    • Added a regression test that verifies cleanup and unsubscribe behavior during connection close events to prevent missed or duplicate subscriptions.

@diegolmello diegolmello temporarily deployed to approve_e2e_testing May 29, 2026 20:52 — with GitHub Actions Inactive
@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f5b21bb7-2fee-4167-98f3-9bc5e378a020

📥 Commits

Reviewing files that changed from the base of the PR and between 19944a4 and 6dd8818.

📒 Files selected for processing (2)
  • app/lib/services/connect.test.ts
  • app/lib/services/connect.ts
✅ Files skipped from review due to trivial changes (1)
  • app/lib/services/connect.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/lib/services/connect.test.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: format

Walkthrough

The PR calls unsubscribeRooms() in the socket 'close' handler to reset the rooms-subscription guard and adds a regression test verifying unsubscribeRooms() is invoked when the SDK stream emits a 'close' event after connect().

Changes

Stream Close Unsubscribe Rooms Guard Reset

Layer / File(s) Summary
Close handler cleanup
app/lib/services/connect.ts
The 'close' event handler now calls unsubscribeRooms() to reset the rooms-subscription guard, with comments documenting the checkAndReopen close/reopen scenario.
Regression test for close-event cleanup
app/lib/services/connect.test.ts
Adds import of unsubscribeRooms and a regression test that resets mocks/store/stream-stop tracking, runs connect(), invokes the first registered 'close' handler, and asserts unsubscribeRooms() is called exactly once.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested labels

type: bug

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: re-subscribe rooms stream after forced socket reopen' clearly and concisely summarizes the main change: resetting the rooms subscription guard after socket reopening.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • SUP-1047: Request failed with status code 401

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

iOS Build Available

Rocket.Chat 4.73.0.109000

@OtavioStasiak OtavioStasiak 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.

LGTM

A long background marks the DDP socket stale, so foregrounding triggers
checkAndReopen -> forceReopen, which drops all SDK subscriptions and reopens
the socket without going through connect(). The module-level roomsSubscription
guard therefore stayed set, so subscribeRooms() skipped re-subscribing
stream-notify-user and the rooms list silently stopped reflecting
subscriptions/favorites/reads until a manual reconnect.

Reset the guard from the socket 'close' listener (via unsubscribeRooms), the
same teardown connect() already performs, so the resume-login that follows the
reopen re-subscribes stream-notify-user. Other streams (permissions, presence,
settings, roles) subscribe unconditionally and were never affected.
@diegolmello diegolmello force-pushed the rooms-freeze-android branch from 19944a4 to 6dd8818 Compare June 1, 2026 20:15
@diegolmello diegolmello requested a deployment to approve_e2e_testing June 1, 2026 20:15 — with GitHub Actions Waiting
@diegolmello diegolmello merged commit cd6f2a8 into develop Jun 1, 2026
6 of 7 checks passed
@diegolmello diegolmello deleted the rooms-freeze-android branch June 1, 2026 20:16
steffenkleinle pushed a commit to netzbegruenung/chatbegruenung-app that referenced this pull request Jun 16, 2026
Brings the 4.73.1 release into the single-server line.

Conflict resolution (mirrors the 4.73.0 single-server merge, NATIVE-1205):
- Version files (package.json, build.gradle, Info.plist x2, pbxproj) -> 4.73.1
- android/gradle.properties -> single-server values (APPLICATION_ID=chat.rocket.reactnative,
  VERSIONCODE=1, keystore block)
- Firebase configs kept deleted (google-services.json, GoogleService-Info.plist,
  debug strings.xml)
- connect.ts / connect.test.ts -> 4.73.1 (single-server merely lacked the
  unsubscribeRooms() close-listener fix RocketChat#7362)
- pnpm-lock.yaml / Podfile.lock -> 4.73.1 (only delta was picker 2.11.1 -> 2.11.4)
- Single-server product customizations intact (app.json hardcoded server,
  disabled NewServerView, disabled ServersList switcher)
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.

2 participants