From a806f2db9960a562a5da36f2d6228bc5e05a4f5a Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Mon, 25 Aug 2025 20:53:50 +0200 Subject: [PATCH] Update scenes to v6.30.4 canary and document profile isolation (#110112) * Update scenes to v6.30.4 canary and document profile isolation - Bump @grafana/scenes and @grafana/scenes-react to 6.30.4--canary.1225 - Document SceneRenderProfiler overlapping profile handling * Update scenes --- package.json | 4 +- .../dashboard-render-performance-profiling.md | 79 +++++++++++++++++++ yarn.lock | 22 +++--- 3 files changed, 92 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 388b925397a..d474a542bc7 100644 --- a/package.json +++ b/package.json @@ -291,8 +291,8 @@ "@grafana/plugin-ui": "0.10.9", "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "^6.30.0", - "@grafana/scenes-react": "^6.30.0", + "@grafana/scenes": "6.30.4", + "@grafana/scenes-react": "6.30.4", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/public/app/features/dashboard/services/dashboard-render-performance-profiling.md b/public/app/features/dashboard/services/dashboard-render-performance-profiling.md index 465fdcc4465..2320e28be16 100644 --- a/public/app/features/dashboard/services/dashboard-render-performance-profiling.md +++ b/public/app/features/dashboard/services/dashboard-render-performance-profiling.md @@ -234,6 +234,84 @@ if (frameLength > TAB_INACTIVE_THRESHOLD) { This fallback catches cases where visibility events might be missed and prevents recording of artificially long frame times (hours instead of milliseconds) that occur when `requestAnimationFrame` callbacks resume after tab reactivation. +### Profile Isolation and Overlapping Interactions + +To ensure accurate performance measurements, the `SceneRenderProfiler` implements profile isolation to handle rapid user interactions: + +#### Understanding Trailing Frame Recording + +After the main interaction completes, the profiler continues to record "trailing frames" for 2 seconds (POST_STORM_WINDOW) to capture any delayed rendering effects. This ensures complete performance measurement including: + +- Delayed DOM updates +- Asynchronous rendering operations +- Secondary effects from the initial interaction + +#### Problem: Mixed Performance Data + +When users perform rapid interactions during this 2-second trailing frame window (e.g., quickly changing time ranges or triggering a refresh), the performance data from multiple actions could be mixed into a single profile. This led to: + +- Inaccurate performance measurements +- Profile events that never completed +- Crumbs from different interactions being combined +- Trailing frames from one interaction being attributed to another + +#### Solution: Automatic Profile Cancellation + +Starting with `@grafana/scenes` v6.30.4, the profiler automatically cancels the current profile when a new interaction begins while trailing frames are still being recorded: + +```javascript +// When new profile is requested while still recording trailing frames +if (this.#trailAnimationFrameId) { + this.cancelProfile(); + this._startNewProfile(name, true); // true = forced profile +} else { + this.addCrumb(name); +} +``` + +This ensures: + +- Each interaction gets its own isolated measurement +- No mixing of performance data between different user actions +- Clean separation of interaction metrics + +#### Profile Start Types + +The profiler now distinguishes between two types of profile starts: + +1. **Clean Start**: Profile started when no other profile is active +2. **Forced Start (Interrupted)**: Profile started by cancelling a previous active profile + +This information is logged in debug mode: + +``` +SceneRenderProfiler: Profile started[forced]: {origin: "refresh", crumbs: []} +SceneRenderProfiler: Profile started[clean]: {origin: "dashboard_view", crumbs: []} +``` + +Additionally, when a profile is cancelled due to overlapping interactions: + +``` +SceneRenderProfiler: Cancelled recording frames, new profile started +``` + +#### Example Scenario + +1. User changes time range (profile starts) +2. Dashboard finishes loading after 500ms (main profile complete) +3. Profiler continues recording trailing frames to capture delayed effects +4. At 1 second, user clicks refresh button +5. Without this fix: Refresh would be added as a crumb to the time range profile +6. With this fix: Time range profile is cancelled, new refresh profile starts cleanly + +This fix is particularly important for dashboards with: + +- Auto-refresh enabled +- Slow API responses +- Rapid user interactions + +Without profile isolation, these scenarios could result in profiles that never complete and mix data from multiple unrelated interactions. + ## Related Documentation - [PR #858 - Add SceneRenderProfiler to scenes](https://github.com/grafana/scenes/pull/858) @@ -246,3 +324,4 @@ This fallback catches cases where visibility events might be missed and prevents - [PR #1209 - SceneRenderProfiler: Only capture network requests within measurement window](https://github.com/grafana/scenes/pull/1209) - [PR #1211 - SceneRenderProfiler: Improve profiler accuracy by adding cancellation and skipping inactive tabs](https://github.com/grafana/scenes/pull/1211) - [PR #1212 - SceneQueryController: Fix profiler query controller registration on scene re-activation](https://github.com/grafana/scenes/pull/1212) +- [PR #1225 - SceneRenderProfiler: Handle overlapping profiles by cancelling previous profile](https://github.com/grafana/scenes/pull/1225) diff --git a/yarn.lock b/yarn.lock index 65b8f22dd32..dfd8656a6b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3586,11 +3586,11 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes-react@npm:^6.30.0": - version: 6.30.1 - resolution: "@grafana/scenes-react@npm:6.30.1" +"@grafana/scenes-react@npm:6.30.4": + version: 6.30.4 + resolution: "@grafana/scenes-react@npm:6.30.4" dependencies: - "@grafana/scenes": "npm:6.30.1" + "@grafana/scenes": "npm:6.30.4" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3602,13 +3602,13 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/695c61665f38f09f6b49552a32caf1fbe6a3209d9df7039fd9110dcbda9e2031e41d53b7e471021e779bee78f8f27a3978fed96f9e70a07f2157e25f96a81937 + checksum: 10/47a447459e0e432db40ebb8cbe9dbae24d4f94d6c558e53bc0ef79f21f91d219650af97fa7c9f5bcbf5ef09f34de900d6db69f22bd897465371ec9fc696f68b1 languageName: node linkType: hard -"@grafana/scenes@npm:6.30.1, @grafana/scenes@npm:^6.30.0": - version: 6.30.1 - resolution: "@grafana/scenes@npm:6.30.1" +"@grafana/scenes@npm:6.30.4": + version: 6.30.4 + resolution: "@grafana/scenes@npm:6.30.4" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3628,7 +3628,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/6c50a31330ecb674de6664d6e119e54dee7ecee50925a71870c0a08562e4b3d5614e56e34008d6710e65ef03a8220ba2e9d811804b8a001392de46ef745a2e75 + checksum: 10/7a05dc8e8a01cc3b92e0a02b0a8d3fd0af2cf420840dd25daf5939d22669212cd96a7d91bf1caf7fbae3a5530ace519c730141664fac17220869117d4ccbec0a languageName: node linkType: hard @@ -18320,8 +18320,8 @@ __metadata: "@grafana/plugin-ui": "npm:0.10.9" "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" - "@grafana/scenes": "npm:^6.30.0" - "@grafana/scenes-react": "npm:^6.30.0" + "@grafana/scenes": "npm:6.30.4" + "@grafana/scenes-react": "npm:6.30.4" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/test-utils": "workspace:*"