Skip to content

[ZEPPELIN-6532] Complete destroy$ in paragraph ngOnDestroy to stop leaking subscriptions#5322

Open
JangAyeon wants to merge 1 commit into
apache:masterfrom
JangAyeon:ZEPPELIN-6532
Open

[ZEPPELIN-6532] Complete destroy$ in paragraph ngOnDestroy to stop leaking subscriptions#5322
JangAyeon wants to merge 1 commit into
apache:masterfrom
JangAyeon:ZEPPELIN-6532

Conversation

@JangAyeon

@JangAyeon JangAyeon commented Jul 19, 2026

Copy link
Copy Markdown

What is this PR for?

Destroying a notebook paragraph did not tear down its own long-lived subscriptions or the shortcut key listeners it registered. ngOnDestroy() only called super.ngOnDestroy(), which (via MessageListenersManager) unsubscribes
the @MessageListener subscriptions but never touches destroy$. Subscriptions gated on takeUntil(this.destroy$) - keyBinderService.keyEvent(), angularContextManager.runParagraphAction(), and .contextChanged() - are on singleton services, so a destroyed paragraph instance stayed reachable and kept receiving callbacks after being removed from the DOM. The shortcut keydown listeners registered by KeyBinder via shortcutService.bindShortcut() were also never released.

This PR emits and completes destroy$ in ngOnDestroy, after super.ngOnDestroy(), matching the pattern already used in result.component.ts and dynamic-forms.component.ts.

What type of PR is it?

Bug Fix

Todos

  • Emit and complete destroy$ in paragraph ngOnDestroy

What is the Jira issue?

ZEPPELIN-6532

How should this be tested?

  • cd zeppelin-web-angular && npm run lint
  • At runtime, subscribe to a paragraph component's destroy$, then remove it (or navigate away): before the fix destroy$ never completes even though the paragraph is removed from the DOM; after the fix it completes on destroy, and the keyEvent/runParagraphAction/contextChanged subscriptions stop firing along with the shortcut keydown listeners.

Questions:

  • Does the license files need to update? No
  • Is there breaking changes for older versions? No
  • Does this needs documentation? No

…aking subscriptions

ngOnDestroy() only called super.ngOnDestroy(), which tears down the @MessageListener subscriptions and nothing else. destroy$ was never emitted or completed, so subscriptions gated on takeUntil(this.destroy$) - keyBinderService.keyEvent(), angularContextManager.runParagraphAction(), and .contextChanged() - kept running against singleton services after a paragraph was destroyed, and the keydown listeners KeyBinder registered through shortcutService.bindShortcut() were never released.

Emit and complete destroy$ in ngOnDestroy after super.ngOnDestroy(), matching the pattern already used in result.component.ts and dynamic-forms.component.ts.

@tbonelee tbonelee 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. Clean, minimal fix for the leak.

Verified the reasoning holds:

  • destroy$ is a local Subject (paragraph.component.ts:147) that was never completed, so the takeUntil(this.destroy$) subscriptions on singleton services (keyEvent(), runParagraphAction(), contextChanged()) kept a destroyed paragraph alive.
  • The shortcut listeners are released too: KeyBinder receives destroy$ and gates bindShortcut(...) with takeUntil(this.destroySubject) (key-binder.ts:53), so completing destroy$ tears them down.
  • All .subscribe() sites in the component are gated by takeUntil(destroy$), so no leak remains after this change.

Keeping super.ngOnDestroy() first is correct, and the destroy$.next(); destroy$.complete(); pattern matches the existing usage in dynamic-forms.component.ts.

@tbonelee

Copy link
Copy Markdown
Contributor

Small request: the Jira link in the PR description points to ZEPPELIN/6532, which is a broken URL. Could you fix it to ZEPPELIN-6532 so it resolves to the issue?

https://issues.apache.org/jira/browse/ZEPPELIN-6532

@JangAyeon

Copy link
Copy Markdown
Author

Small request: the Jira link in the PR description points to ZEPPELIN/6532, which is a broken URL. Could you fix it to ZEPPELIN-6532 so it resolves to the issue?

https://issues.apache.org/jira/browse/ZEPPELIN-6532

Fixed the Jira link in the PR description — it now points to ZEPPELIN-6532 and resolves correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants