Skip to content

Conversation

@pachara-strike
Copy link

@pachara-strike pachara-strike commented Jan 20, 2026

SUMMARY

Fixes memory leak in @superset-ui/embedded-sdk where fetchGuestToken refresh timers continue running after unmount().

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A

TESTING INSTRUCTIONS

  1. Create a test application that uses embedDashboard()
  2. Call unmount() after embedding
  3. Verify no setTimeout timers continue running
  4. Check browser dev tools for continued network requests (should be none)

ADDITIONAL INFORMATION

@codeant-ai-for-open-source
Copy link
Contributor

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@bito-code-review
Copy link
Contributor

bito-code-review bot commented Jan 20, 2026

Code Review Agent Run #31b020

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 0a95a42..0a95a42
    • superset-embedded-sdk/src/index.ts
  • Files skipped - 2
    • superset-embedded-sdk/package-lock.json - Reason: Filter setting
    • superset-embedded-sdk/package.json - Reason: Filter setting
  • Tools
    • Eslint (Linter) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@codeant-ai-for-open-source
Copy link
Contributor

CodeAnt AI finished reviewing your PR.

@netlify
Copy link

netlify bot commented Jan 20, 2026

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit df6a8a8
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/696f3ede178d5b00086420c5
😎 Deploy Preview https://deploy-preview-37280--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@bito-code-review
Copy link
Contributor

bito-code-review bot commented Jan 20, 2026

Code Review Agent Run #c29043

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 0a95a42..df6a8a8
    • superset-embedded-sdk/src/index.ts
  • Files skipped - 2
    • superset-embedded-sdk/package-lock.json - Reason: Filter setting
    • superset-embedded-sdk/package.json - Reason: Filter setting
  • Tools
    • Eslint (Linter) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@pachara-strike
Copy link
Author

Hi @msyavuz , could you help review this PR. It's from this issue #34529

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a memory leak in the @superset-ui/embedded-sdk package where guest token refresh timers continued running after calling unmount(). The fix introduces timer tracking and cleanup to ensure proper resource disposal.

Changes:

  • Added timer ID tracking for the fetchGuestToken refresh mechanism
  • Implemented timer cleanup in the unmount() function
  • Bumped package version from 0.3.0 to 0.3.1

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
superset-embedded-sdk/src/index.ts Added refreshTokenTimerId variable to track setTimeout timers and clear them in unmount()
superset-embedded-sdk/package.json Version bump to 0.3.1
superset-embedded-sdk/package-lock.json Version bump to 0.3.1 (lockfile update)
Files not reviewed (1)
  • superset-embedded-sdk/package-lock.json: Language not supported

Comment on lines 253 to 260
async function refreshGuestToken() {
const newGuestToken = await fetchGuestToken();
ourPort.emit('guestToken', { guestToken: newGuestToken });
setTimeout(refreshGuestToken, getGuestTokenRefreshTiming(newGuestToken));
refreshTokenTimerId = setTimeout(refreshGuestToken, getGuestTokenRefreshTiming(newGuestToken));
}
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

There's a race condition in the timer cleanup logic. If unmount() is called while refreshGuestToken() is executing (after the timer has fired but before the new timer is set at line 256), the new timer won't be cleared.

To fix this, consider adding a flag to prevent setting new timers after unmount is called, or setting refreshTokenTimerId to null immediately when the timer fires, or clearing it at the start of refreshGuestToken before the async operation.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

Fixed

Comment on lines 282 to 284
if (refreshTokenTimerId) {
clearTimeout(refreshTokenTimerId);
}
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The new timer cleanup functionality in the unmount method lacks test coverage. Consider adding tests to verify that clearTimeout is called when unmount is invoked, and that no timers continue running after unmount.

Copilot uses AI. Check for mistakes.
@pachara-strike pachara-strike force-pushed the embedded-sdk-clear-refresh-token-timer branch from df6a8a8 to 28387f5 Compare January 22, 2026 10:02
clearTimeout(refreshTokenTimerId);
refreshTokenTimerId = 'UNMOUNTED';

mountPoint.replaceChildren();
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: unmount() clears the refresh timer but does not stop or close the Switchboard/message port, so the message channel and any defined methods/listeners can remain active after unmount, causing memory leaks and continued message handling. Stop the switchboard and close its underlying port (if present) during unmount. [resource leak]

Severity Level: Critical 🚨
- ❌ Message ports/listeners may leak after unmount.
- ⚠️ Long-running host pages accumulate memory leaks.
- ⚠️ Embedded comms may still receive messages unexpectedly.
Suggested change
mountPoint.replaceChildren();
// Stop the switchboard and close the underlying MessagePort if available to avoid
// leaving listeners/ports open after unmount.
try {
(ourPort as any).stop?.();
} catch (e) {
// ignore stop errors
}
try {
(ourPort as any).port?.close?.();
} catch (e) {
// ignore close errors
}
Steps of Reproduction ✅
1. Call embedDashboard() (superset-embedded-sdk/src/index.ts:118) which eventually calls
ourPort.start() at line 266 to begin iframe comms.

2. Interact with the embedded dashboard; ourPort.defineMethod(...) is used (lines 267-279)
and communication channel remains active.

3. Call unmount() (lines 282-289). Current unmount clears the refresh timer (lines
285-286) and removes iframe (line 288) but does not call any Switchboard stop/port close
methods.

4. Because ourPort.was started at line 266 and no stop/close is invoked on unmount, the
underlying MessageChannel/handlers defined by Switchboard can remain active, causing
retained listeners/ports and potential memory leaks.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-embedded-sdk/src/index.ts
**Line:** 288:288
**Comment:**
	*Resource Leak: `unmount()` clears the refresh timer but does not stop or close the Switchboard/message port, so the message channel and any defined methods/listeners can remain active after unmount, causing memory leaks and continued message handling. Stop the switchboard and close its underlying port (if present) during unmount.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.

@bito-code-review
Copy link
Contributor

bito-code-review bot commented Jan 22, 2026

Code Review Agent Run #f5eb83

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 28387f5..28387f5
    • superset-embedded-sdk/src/index.ts
  • Files skipped - 2
    • superset-embedded-sdk/package-lock.json - Reason: Filter setting
    • superset-embedded-sdk/package.json - Reason: Filter setting
  • Tools
    • Eslint (Linter) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

ourPort.emit('guestToken', { guestToken });
log('sent guest token');

let refreshTokenTimerId: ReturnType<typeof setTimeout> | 'INITIAL' | 'UNMOUNTED' = 'INITIAL';
Copy link
Member

Choose a reason for hiding this comment

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

This looks a bit off. Do we need this and UNMOUNTED check under refreshGuestToken?

Copy link
Author

Choose a reason for hiding this comment

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

It's to fix race condition problem from this comment #37280 (comment)

It will happen when call unmount function during waiting for new guest token response. So unmount function will clear the old setTimeout and refreshGuestToken will create a new setTimeout.

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.

Embedded Dashboard continues to call fetchGuestToken after unmount() in Angular applications

2 participants