Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(platform-server): destroy PlatformRef when error happens during the bootstrap() phase, e.g. in APP_INIIALIZER - to prevent memory leaks in SSR #58112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

Platonn
Copy link
Contributor

@Platonn Platonn commented Oct 7, 2024

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.dev application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

PlatformRef is not destroyed if an error happens during the bootstrap() phase (e.g. in APP_INITIALIZER). Then the main app's injector is not destroyed and therefore ngOnDestroy hooks of singleton services were not called on the end (failure) of SSR.

Note: This could lead to possible memory leaks in custom SSR apps, if their singleton services' ngOnDestroy hooks contained an important teardown logic (e.g. unsubscribing from RxJS observable).

Issue Number: #58111

What is the new behavior?

  • PlatformRef is guaranteed to be destroyed in renderApplication() and renderModule() functions of @angular/platform-server both in the case of successful render and in the case of a failure (resulting in a rejected promise)
  • PLATFORM_DESTROY_LISTENERS that destroys the app's main injector is now set not only in case of renderApplication(), but also in case of renderModule()

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@JeanMeche
Copy link
Member

Hi Krzysztof, thanks for looking into this. Could you please rebase your PR on the main branch (so we can run the CI)

@Platonn
Copy link
Contributor Author

Platonn commented Oct 7, 2024

Thank you @JeanMeche for your reply.
I've rebased with main just now and resolved the code conflicts.

@JeanMeche
Copy link
Member

The changes are breaking the elements pacakge, can you have a look ?

@Platonn Platonn force-pushed the fix/GH-58111 branch 2 times, most recently from 22b7bca to a13f1fb Compare October 7, 2024 22:45
@Platonn
Copy link
Contributor Author

Platonn commented Oct 7, 2024

Thank you @JeanMeche for letting me know.
Now pushed a fix.

Explanation:

  • Before this PR
    • the isApplicationBootstrapConfig() was duck-typing based on the presence of the property platformInjector.
  • In this PR initially
    • I've changed the logic to check the property rootComponent instead, because I wanted to pass the platformInjector in all cases - also in the NgModule flow (in order to setup the PLATFORM_DESTROY_LISTENER later in the bootstrap() function).
    • It turned out to break the behavior of the public API function createApplication() which was tested inside the elements package. The test failed, because no rootComponent was passed in that test case setup as a param of createApplication. Then isApplicationBootstrapConfig() returned false which led into incorrectly executing the NgModule-flow of bootstrap(). Despite someone could perceive omitting the rootComponent as an edge case usage of createApplication(), I broke that default behavior. So needed to fix it
  • The fix
    • So now I've fixed the problem by no-longer duck-typing inside the isApplicationBootstrapConfig() function. Instead, I started passing explicitly a newly-introduced config property BootstrapKind as a required param of the bootstrap() function. btw. It's not a breaking change, because the signature of the bootstrap() function is not a part of the public API, as far as I can understand.

Copy link
Contributor

@alan-agius4 alan-agius4 left a comment

Choose a reason for hiding this comment

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

LGTM, just a couple of NITs

… the `bootstrap()` phase

The `bootstrap()` phase might fail e.g. due to an rejected promise in some `APP_INIIALIZER`.
If `PlatformRef` is not destroyed, then the main app's injector is not destroyed and therefore `ngOnDestroy` hooks of singleton services is not called on the end (failure) of SSR.

This could lead to possible memory leaks in custom SSR apps, if their singleton services' `ngOnDestroy` hooks contained an important teardown logic (e.g. unsubscribing from RxJS observable).

Note: I needed to fix by the way another thing too: now we destroy `moduleRef` when `platformInjector` is destroyed - by setting a `PLATFORM_DESTROY_LISTENER`

fixes angular#58111
@AndrewKushnir
Copy link
Contributor

@Platonn thanks for creating this PR 👍 It looks like there is a failing test (see the test CI job output). Could you please take a look at it when you get a chance?

@AndrewKushnir AndrewKushnir added action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews area: server Issues related to server-side rendering target: patch This PR is targeted for the next patch release labels Oct 8, 2024
@ngbot ngbot bot added this to the Backlog milestone Oct 8, 2024
@JeanMeche
Copy link
Member

JeanMeche commented Oct 8, 2024

@AndrewKushnir It looks like the failing test is flaky. CI is fine after a re-run.
I couldn't reproduce the test-breakage locally.

@AndrewKushnir AndrewKushnir added action: presubmit The PR is in need of a google3 presubmit and removed action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews labels Oct 9, 2024
@AndrewKushnir
Copy link
Contributor

Presubmit.

@AndrewKushnir AndrewKushnir removed the request for review from pkozlowski-opensource October 9, 2024 04:41
@AndrewKushnir AndrewKushnir added action: merge The PR is ready for merge by the caretaker and removed action: presubmit The PR is in need of a google3 presubmit labels Oct 9, 2024
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Nov 9, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: server Issues related to server-side rendering merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note target: minor This PR is targeted for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants