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

perf: prefer use factory instead of use value when possible #12753

Merged

Conversation

H4ad
Copy link
Contributor

@H4ad H4ad commented Nov 15, 2023

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
  • Other... Please describe:

What is the current behavior?

Because of the nature of the ModuleTokenFactory, heavy objects will slow down the initialization, especially when using .proto files.

Issue Number: #12719
Closes #12719

What is the new behavior?

Now, we defer the initialization of the .proto files by using useFactory, this will fix any initialization issue.

image

The second run is with the fix.

I also updated almost all the references for useValue, so this can help avoid the same issue in other places.

Does this PR introduce a breaking change?

  • Yes
  • No

@jmcdo29
Copy link
Member

jmcdo29 commented Nov 15, 2023

Very interesting, but nice to see a solution for this. Great job!

@Tony133
Copy link
Contributor

Tony133 commented Nov 15, 2023

Let's see what Kamil thinks, but ha me I really like this modification. 😉👍

@Tony133
Copy link
Contributor

Tony133 commented Nov 15, 2023

Corrections also need to be made to the tests, see here:
screen

@micalevisk
Copy link
Member

I'd suggest to add some comments on why we are using factory over value providers in those places to prevent on future refactoring on them

Comment on lines -48 to +64
useValue: ExternalContextCreator.fromContainer(container),
useFactory: () => ExternalContextCreator.fromContainer(container),
},
{
provide: ModulesContainer,
useValue: container.getModules(),
useFactory: () => container.getModules(),
},
{
provide: HttpAdapterHost,
useValue: httpAdapterHost,
useFactory: () => httpAdapterHost,
},
{
provide: LazyModuleLoader,
useFactory: lazyModuleLoaderFactory,
},
{
provide: SerializedGraph,
useValue: container.serializedGraph,
useFactory: () => container.serializedGraph,
Copy link
Member

@micalevisk micalevisk Nov 15, 2023

Choose a reason for hiding this comment

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

I notice another good side-effect on changing ExternalContextCreator and SerializedGraph providers to factory:

SerializedGraph#toJSON was called 6x in a very simple nestjs app before these changes, which I think it was useless because it was only invoked due to the name toJSON being known as a special method for JSON.stringify (used by stringify from fast-safe-stringify)

🥳

@coveralls
Copy link

coveralls commented Nov 16, 2023

Pull Request Test Coverage Report for Build 349dfb92-7ead-48ea-8cfa-4a0a9202a4d3

  • 4 of 9 (44.44%) changed or added relevant lines in 4 files are covered.
  • 16 unchanged lines in 2 files lost coverage.
  • Overall coverage decreased (-0.3%) to 91.979%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/common/module-utils/configurable-module.builder.ts 0 1 0.0%
packages/core/injector/internal-core-module/internal-core-module-factory.ts 0 4 0.0%
Files with Coverage Reduction New Missed Lines %
packages/common/module-utils/configurable-module.builder.ts 6 79.03%
packages/core/helpers/external-context-creator.ts 10 86.11%
Totals Coverage Status
Change from base Build 23ebebfc-1ad4-4b2b-8c07-2691151ef178: -0.3%
Covered Lines: 6674
Relevant Lines: 7256

💛 - Coveralls

{ provide: MULTER_MODULE_OPTIONS, useValue: options },
// useFactory is for performance reasons
// see more: https://github.com/nestjs/nest/issues/12738#issuecomment-1810987001
{ provide: MULTER_MODULE_OPTIONS, useFactory: () => options },
Copy link
Member

Choose a reason for hiding this comment

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

With this change, you won't be able to use multiple multer modules in your project (due to equal hash tokens).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, but if the user uses https://docs.nestjs.com/techniques/file-upload#async-configuration, they already have this effect.

Anyone that does not use useValue will have this same issue, so I think we can consider this a minor if we want to release a safer version.

Maybe we can study emit warnings when we detect two modules duplicated (with same hash), so the users can be aware of this behavior.

But this could be better in a follow-up PR, what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kamilmysliwiec
Copy link
Member

Long term we should circle back on something we discussed a while ago - so basically replacing the hashing logic with something very simple (and not ideal but that's the middle ground I guess), for example with a custom function that simply generates a unique ID based on the registered providers (their stringified tokens), imports, and exports - that should be sufficient and will leave us with a (fairly) unique hash and with no requirement for hashing useValue providers. Would you like to create a PR for this (if it all makes sense)?

Eventually, we'll leave that hash for the purpose of diff algorithms (devtools) and just use weak references, dropping the entire "modules redundancy optimization" technique in future major versions.

@H4ad
Copy link
Contributor Author

H4ad commented Nov 17, 2023

@kamilmysliwiec I will create an issue to compile all the viable options to solve this issue based on that previous comment I already made and include your suggestion then we can validate which one is possible to build and which has the best DX.

But as soon I have more time, I can create a PR for this.

@H4ad
Copy link
Contributor Author

H4ad commented Nov 17, 2023

Was not possible to defer RoutesModule due to the issue with the duplicated hash (from what I saw), so I removed that optimization.

@kamilmysliwiec kamilmysliwiec merged commit d165eed into nestjs:master Dec 18, 2023
5 checks passed
@kamilmysliwiec
Copy link
Member

lgtm

@micalevisk
Copy link
Member

micalevisk commented Jan 22, 2024

@H4ad do you think that this change is related with the issue #13076 ?

@H4ad
Copy link
Contributor Author

H4ad commented Jan 22, 2024

Improbable but not impossible, if you have some reproduction, I can investigate.

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.

Avoid serializing buffers when creating module's opaque token
6 participants