[pull] main from MetaMask:main#524
Merged
Merged
Conversation
…s rendering (#26061) ## **Description** Eliminates the empty-screen flash on cold load of the Perps tab by preloading data at app startup and seeding hooks from the controller cache. **What changed:** 1. **Background preloading** — `startMarketDataPreload()` is called from the Wallet tab to fetch market data + user data (positions, orders, account state) via lightweight standalone REST calls, caching results in the controller's transient state. A 5-minute periodic refresh keeps the cache warm. 2. **Cache-seeded hook initialization** — Stream hooks (`usePerpsLivePositions`, `usePerpsLiveOrders`, `usePerpsLiveAccount`) and `usePerpsMarkets` use lazy `useState` initializers that read from the controller cache. If preloaded data exists, the first render shows real data instead of a skeleton. 3. **Unified cache utility** — `hasPreloadedUserData(field)` and `getPreloadedUserData(field)` provide a single place for cache-existence checks across all hooks (positions, orders, account state, and market data). No client-side TTL — the controller's 5-minute preload cycle manages freshness. 4. **Stream channel initialization guards** — Channels defer WebSocket subscriptions until the controller is initialized (retrying every 200ms, max 150 attempts). This prevents doomed subscriptions that would permanently block data delivery. 5. **Progressive loading** — `PerpsConnectionProvider` no longer blocks with a full-screen "Connecting to Perps" skeleton. Children render immediately with cache-seeded data; per-row skeletons appear only when no cached data is available (e.g., first app install) and resolve once WebSocket data arrives. 6. **Sentry traces for preload timing** — New `MarketDataPreload` and `UserDataPreload` traces measure end-to-end preload duration, reporting to Sentry for cold-start performance monitoring. 7. **Hardened subscribe methods** — All 8 `subscribeTo*()` methods now use `getActiveProviderOrNull()` instead of `getActiveProvider()`, returning early when no provider is available. This prevents `CLIENT_NOT_INITIALIZED` throws during cold-start when preload fires before WebSocket initialization. 8. **Skip user data preload when WS connected** — `preloadUserData()` bails out early if the WebSocket is already connected, avoiding redundant REST fetches that would be immediately overwritten by live stream data. ## **Changelog** CHANGELOG entry: Preloaded Perps market and user data at startup for instant rendering ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Perps cold load performance Scenario: User opens Perps tab for the first time Given the user is on the Wallet tab And the app has been open for at least a few seconds (preload has run) When user navigates to the Perps tab Then markets list renders immediately with real data (no skeleton flash) And positions/orders/account state render from cache And live WebSocket data replaces cache within ~1-2s Scenario: User switches accounts while on Perps tab Given the user is on the Perps tab with data displayed When user switches to a different account Then cached user data is cleared And new account's data is preloaded And UI updates to show new account's positions/orders Scenario: Preloaded data older than 60s still renders Given the user opened the app 3 minutes ago (preload ran at startup) And the 5-minute refresh has not yet triggered When user navigates to the Perps tab Then markets and positions render from cache (no skeleton) And WebSocket data replaces cache shortly after ``` ## **Screenshots/Recordings** ### **Before** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/d3edc121-d9b2-48a7-bd4e-ebeaf39efb0d ### **After** Uploading after_ios16.mp4… <!-- [screenshots/recordings] --> ## **Performance Results** ### UI Render Speed (cold start — time to show market data) | Scenario | `main` | This PR | Gain | |---|---|---|---| | iPhone Tab View | ~1.7s | **0ms** (cache) | **1.7s faster** | | iPhone Home View | ~3.2s | **0ms** (cache) | **3.2s faster** | | Android Home View | ~2.3–2.6s | **1ms** (cache) | **2.3–2.6s faster** | Cache decouples UI rendering from the WebSocket pipeline — users see real data instantly, WS refreshes in the background. ### Sentry Production Baselines (Android p50, last 3 releases) | Metric | v7.61.6 | v7.62.2 | v7.63.1 | |---|---|---|---| | Perps Tab View | 818ms | 676ms | 538ms | | WS Connection | 5320ms | 7876ms | 9023ms | Production WS connections are 5–9x slower than local (real network latency) — cache impact will be **even larger** in production since it eliminates the wait entirely. ## **Performance measurements** All traces are instrumented and report to Sentry automatically. | Sentry trace name | Where it fires | What it measures | Expected improvement | | ------------------------ | ------------------------------------------------------------------ | ---------------------------------------------------------- | ---------------------------------------------------- | | `PerpsTabView` | `PerpsTabView.tsx:70-77` | Tab mount → positions loaded + account balance available | Near-instant (cache-seeded) vs ~1-2 s (cold WS wait) | | `PerpsMarketListView` | `PerpsHomeView.tsx:176-179`, `PerpsMarketListView.tsx:212-215` | Render → markets list populated | Near-instant vs ~1-2 s | | `MarketDataPreload` | `PerpsController.ts` — `startMarketDataPreload()` | REST fetch of all market metadata during background preload | New trace (baseline measurement) | | `UserDataPreload` | `PerpsController.ts` — `preloadUserData()` | REST fetch of positions, orders, account state | New trace (baseline measurement) | ### How to compare **Sentry dashboard:** 1. Open the Sentry Performance dashboard for the project. 2. Filter by transaction name `PerpsTabView` or `PerpsMarketListView`. 3. Compare p50 / p95 durations between this branch and `main` (or the previous release). **Dev build (local):** ```bash adb logcat | grep PERPSMARK_SENTRY ``` Each completed trace logs `PERPSMARK_SENTRY PerpsScreen: <traceName> completed` with duration context. ## **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 - [x] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches Perps data-fetching and WebSocket subscription timing across multiple hooks/channels; regressions could cause stale/incorrect cache usage or missed subscriptions, though changes are UI/performance-focused and not security-sensitive. > > **Overview** > Improves Perps cold-start UX by **preloading market + user data into `PerpsController.state`** and seeding initial renders from that cache (markets, positions, orders, account state) so screens can paint real data immediately instead of showing skeletons. > > Adds a shared cache utility (`hasCachedPerpsData.ts`) with *TTL + account-matching checks* for user-scoped data, updates stream hooks (`usePerpsLivePositions`/`Orders`/`Account`) and `usePerpsMarkets` to use lazy `useState` initializers from the controller cache, and refactors market filtering/sorting into `filterAndSortMarkets`. > > Hardens streaming/connect behavior by deferring channel connections until initialization (`ensureReady`/`deferConnect` + retry limits, including candles), using controller-level preloaded market data in `MarketDataChannel`, removing the full-screen Perps connection skeleton (children render immediately; unmount only when `isVisible === false`), guarding REST fills fetch in `usePerpsHomeData` by connection readiness, and starting/stopping background `startMarketDataPreload()` from the Wallet tab when Perps is enabled. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit bc73227. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Vinicius Stevam <45455812+vinistevam@users.noreply.github.com> Co-authored-by: javiergarciavera <76975121+javiergarciavera@users.noreply.github.com> Co-authored-by: Nico MASSART <NicolasMassart@users.noreply.github.com> Co-authored-by: George Weiler <georgejweiler@gmail.com> Co-authored-by: Gustavo Antunes <17601467+gantunesr@users.noreply.github.com> Co-authored-by: Aslau Mario-Daniel <marioaslau@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )