Skip to content
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

fix(signals): use Injector of rxMethod instance caller if available #4529

Merged

Conversation

rainerhahnekamp
Copy link
Contributor

Ensure that an instance of rxMethod uses the Injector of the caller where the instance was invoked, rather than the injector of the node where rxMethod was created.

This change addresses a potential memory leak where a SignalStore method, generated by rxMethod and provided at the root level, continues to track a signal via its effect using the RootInjector. In cases where the component calling the method is destroyed, the Signal remains tracked, leading to unintended behavior and memory retention.

With this commit, rxMethod now prioritizes the injector of the instance caller, falling back to the creator's injector only if no injection context exists. Additionally, a custom injector can be provided by the caller and will take precedence when specified.

For Observable, since it has a different completion mechanism, the instance caller is still responsible for handling unsubscription or completion.

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[x] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] Other... Please describe:

What is the current behavior?

Closes #4528

What is the new behavior?

Does this PR introduce a breaking change?

[ ] Yes
[x] No

Copy link

netlify bot commented Sep 22, 2024

Deploy Preview for ngrx-io canceled.

Name Link
🔨 Latest commit 1ffc0c7
🔍 Latest deploy log https://app.netlify.com/sites/ngrx-io/deploys/66f7e4c8badde500086ed03e

@rainerhahnekamp rainerhahnekamp force-pushed the fix/signals/rx-method-unclosed-effects branch from c207a69 to 7286585 Compare September 22, 2024 14:59
Ensure that an instance of `rxMethod` uses the `Injector` of the caller where
the instance was invoked, rather than the injector of the node where `rxMethod`
was created.

This change addresses a potential memory leak where a `SignalStore` method,
generated by `rxMethod` and provided at the root level, continues to track a
signal via its `effect` using the `RootInjector`. In cases where the component
calling the method is destroyed, the `Signal` remains tracked, leading to
unintended behavior and memory retention.

With this commit, `rxMethod` now prioritizes the injector of the instance
caller, falling back to the creator's injector only if no injection context
exists. Additionally, a custom injector can be provided by the caller and will
take precedence when specified.

For `Observable`, since it has a different completion mechanism, the instance
caller is still responsible for handling unsubscription or completion.
@rainerhahnekamp rainerhahnekamp force-pushed the fix/signals/rx-method-unclosed-effects branch from 7286585 to 720ec77 Compare September 22, 2024 15:00
Copy link
Member

@markostanimirovic markostanimirovic left a comment

Choose a reason for hiding this comment

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

Left a few suggestions. It will be useful to add a concise section on this topic to the RxJS Integration page.

modules/signals/rxjs-interop/src/rx-method.ts Outdated Show resolved Hide resolved
@rainerhahnekamp
Copy link
Contributor Author

@markostanimirovic, I've incorporated all your suggestions and fixed the issues with the source subscription. As a result, the current version of rxMethod has fewer changes.

If you are OK with the implementation, I'd do a last push and add the addition for the docs.

@markostanimirovic markostanimirovic changed the title fix(signals): use Injector of rxMethod instance caller fix(signals): use Injector of rxMethod instance caller if available Sep 28, 2024
@markostanimirovic markostanimirovic force-pushed the fix/signals/rx-method-unclosed-effects branch 2 times, most recently from 9c9913a to bb79531 Compare September 28, 2024 01:11
@markostanimirovic markostanimirovic force-pushed the fix/signals/rx-method-unclosed-effects branch from bb79531 to b3fcf82 Compare September 28, 2024 01:21
Copy link
Member

@markostanimirovic markostanimirovic left a comment

Choose a reason for hiding this comment

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

I've added the same behavior for observables - unsubscribe from an instance subscription when an injector is destroyed.

@timdeschryver timdeschryver merged commit ffc1d87 into ngrx:main Sep 28, 2024
11 checks passed
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.

@ngrx/signals: Potential memory leak in rxMethod
3 participants