chore(runway): cherry-pick fix(perps): connection-aware ensureReady() to fix stale cache on slow connections cp-7.67.0#26334
Conversation
… to fix stale cache on slow connections cp-7.67.0 (#26324) ## **Description** Fixes [TAT-2597](https://consensys-mesh.atlassian.net/browse/TAT-2597) and [TAT-2598](https://consensys-mesh.atlassian.net/browse/TAT-2598): After the preload PR merged, slow connections caused StreamChannels to exhaust 150 polling retries (30s) in `ensureReady()` and silently give up, leaving users with stale REST cache and no live WebSocket data — positions not appearing after trade, missing prices. **Root Cause:** `StreamChannel.ensureReady()` used blind polling (`isReady` every 200ms × 150 retries) with no awareness of WebSocket connection state. On slow connections, the connection had not even established yet, so polling burned through all retries before data could arrive. **Fix:** - `PerpsConnectionManager.waitForConnection()` — exposes init/reconnect promises so channels can `await` instead of blind-polling - `StreamChannel.ensureReady()` — detects `isConnecting` state and awaits the connection promise via `awaitConnectionThenConnect()` **Result:** PriceStreamChannel retries dropped from **33 → 0** on device after this fix. ## **Changelog** CHANGELOG entry: Fixed stale cache on slow connections where positions and prices were not updating after a trade ## **Related issues** Fixes: [TAT-2597](https://consensys-mesh.atlassian.net/browse/TAT-2597), [TAT-2598](https://consensys-mesh.atlassian.net/browse/TAT-2598) ## **Manual testing steps** ```gherkin Feature: Perps live data on slow connections Scenario: user opens a trade on a slow connection Given the app is connected to a slow 3G network And the user has navigated to the Perps trading screen When user opens a new position Then the position appears immediately in the positions list And price stream connects without excessive retries Scenario: user recovers from network drop Given the user is viewing live perps positions And the network connection drops momentarily When the network connection is restored Then live WebSocket data resumes without stale cache ``` ## **Screenshots/Recordings** ### **Before** <!-- PriceStreamChannel: 33 retries before data appears, positions missing on slow connections --> ### **After** <!-- PriceStreamChannel: 0 retries, positions appear immediately --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. [TAT-2597]: https://consensyssoftware.atlassian.net/browse/TAT-2597?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [TAT-2598]: https://consensyssoftware.atlassian.net/browse/TAT-2598?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [TAT-2597]: https://consensyssoftware.atlassian.net/browse/TAT-2597?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches Perps connection/stream reconnection timing and retry logic; mistakes could cause missed subscriptions or delayed real-time updates, though changes are localized and well-covered by tests. > > **Overview** > Prevents Perps stream channels from burning through retry polling on slow connections by making `StreamChannel.ensureReady()` detect `isConnecting` and wait on the connection manager before retrying `connect()`. > > Adds `PerpsConnectionManager.waitForConnection()` (awaits init/reconnect promises, swallowing rejections) and introduces `awaitConnectionThenConnect()` with a sentinel timer to avoid duplicate awaits, plus a small `deferConnect()` timer cleanup fix and a shared `PERPS_CONSTANTS.ConnectRetryDelayMs` constant. > > Expands unit tests to cover the new await/guard behavior (duplicate-await prevention, resolve/reject fallbacks) and updates market-data channel tests to use the new retry delay constant. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 7e0d599. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - base branch is not main (base: release/7.67.0) All E2E tests pre-selected. |
| ); | ||
| this.deferConnect(PERPS_CONSTANTS.ConnectRetryDelayMs); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Dead .catch() handler due to error-swallowing waitForConnection
Medium Severity
The .catch() handler in awaitConnectionThenConnect is unreachable dead code. waitForConnection() wraps both initPromise and pendingReconnectPromise in try-catch blocks that swallow all errors, so the returned promise always resolves — never rejects. The "connection failed, falling back to polling" log message will never appear, making connection failures harder to diagnose. The system still recovers because the .then() path calls connect() which re-enters ensureReady() and eventually reaches deferConnect(), but the explicit error-handling intent is silently bypassed.
Additional Locations (1)
|
|
No release label on PR. Adding release label release-7.67.0 on PR, as PR was cherry-picked in branch 7.67.0. |





Description
Fixes TAT-2597
and TAT-2598:
After the preload PR merged, slow connections caused StreamChannels to
exhaust 150 polling retries (30s) in
ensureReady()and silently giveup, leaving users with stale REST cache and no live WebSocket data —
positions not appearing after trade, missing prices.
Root Cause:
StreamChannel.ensureReady()used blind polling(
isReadyevery 200ms × 150 retries) with no awareness of WebSocketconnection state. On slow connections, the connection had not even
established yet, so polling burned through all retries before data could
arrive.
Fix:
PerpsConnectionManager.waitForConnection()— exposes init/reconnectpromises so channels can
awaitinstead of blind-pollingStreamChannel.ensureReady()— detectsisConnectingstate andawaits the connection promise via
awaitConnectionThenConnect()Result: PriceStreamChannel retries dropped from 33 → 0 on device
after this fix.
Changelog
CHANGELOG entry: Fixed stale cache on slow connections where positions
and prices were not updating after a trade
Related issues
Fixes: TAT-2597,
TAT-2598
Manual testing steps
Screenshots/Recordings
Before
After
Pre-merge author checklist
Docs and MetaMask Mobile
Coding
Standards.
if applicable
guidelines).
Not required for external contributors.
Pre-merge reviewer checklist
app, test code being changed).
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Note
Medium Risk
Changes connection/retry timing and sequencing for Perps WebSocket subscriptions; regressions could delay or prevent live data if the new await/sentinel logic misfires under edge cases (disconnects, rapid resubscribe).
Overview
Perps stream channels now become connection-aware:
StreamChannel.ensureReady()detectsPerpsConnectionManager'sisConnectingstate and waits on a newwaitForConnection()promise, then retriesconnect()(with duplicate-wait suppression and polling fallback on rejection).Retry scheduling was tightened by clearing
deferConnecttimers on fire and centralizing the retry delay viaPERPS_CONSTANTS.ConnectRetryDelayMs;MarketDataChannelnow uses this constant as well. Tests were expanded to cover the new await/deferral behavior and the newPerpsConnectionManager.waitForConnection()contract.Written by Cursor Bugbot for commit 39e206b. This will update automatically on new commits. Configure here.
43cf1d8