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(core,microservices): inject the context when the tree is not durable #10809

Merged

Conversation

micalevisk
Copy link
Member

@micalevisk micalevisk commented Jan 5, 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:

regression introduce at v9.1.1

What is the current behavior?

When injecting REQUEST for non-durable providers, its value is always being context payload even when the injectable chain is not durable, like this:

@Injectable({ scope: Scope.REQUEST, durable: false })
class AppService {
  constructor(@Inject(REQUEST) private readonly req: any) {
    console.log('Is req fasly?', !!req === false) // true but should be false
  }

  isReqDefined() {
    return typeof this.req !== 'undefined' // false but should be true
  }
}

@Controller() // request-scoped but not durable, due to its dependency
class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello() {
    return {
      is_req_defined: this.appService.isReqDefined(),
    }
  }
}

What is the new behavior?

non-durable providers can inject the REQUEST (or CONTEXT. I didn't tested this patch with CONTEXT tho) regardless of the ContextIdStrategy#attach. I'm under the assumption that the context id being resolved doesn't affect the REQUEST provider for a non-durable provider.

You can try this patch:

git clone -b with-10809 https://gitlab.com/micalevisk/nestjs-bug-pr-10793
npm ci
npm start

./request.sh

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

After digging a bit into the source, I didn't find any other way to fix that bug other than checking if the tree is durable in order to define what would be the value for REQUEST/CONTEXT provider.

@coveralls
Copy link

coveralls commented Jan 5, 2023

Pull Request Test Coverage Report for Build eb39fb09-4213-4d70-b662-1e7d6091c253

  • 6 of 9 (66.67%) changed or added relevant lines in 2 files are covered.
  • 11 unchanged lines in 2 files lost coverage.
  • Overall coverage decreased (-0.002%) to 93.407%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/microservices/listeners-controller.ts 4 5 80.0%
packages/core/router/router-explorer.ts 2 4 50.0%
Files with Coverage Reduction New Missed Lines %
packages/microservices/listener-metadata-explorer.ts 2 87.1%
packages/core/injector/container.ts 9 88.89%
Totals Coverage Status
Change from base Build 3995954d-8a28-41bd-aed6-d1836b737f1e: -0.002%
Covered Lines: 6205
Relevant Lines: 6643

💛 - Coveralls

@vizio360
Copy link
Contributor

vizio360 commented Jan 12, 2023

@micalevisk I've created a small test for this but it seems to be working as expected in the most recent nest master branch.

Code here https://github.com/vizio360/nest/pull/1/files

Unless I misunderstood the problem.

@vizio360
Copy link
Contributor

vizio360 commented Jan 12, 2023

@micalevisk I've created a small test for this but it seems to be working as expected in the most recent nest master branch.

Code here https://github.com/vizio360/nest/pull/1/files

Unless I misunderstood the problem.

Actually I didn't really test it properly. I've not set up the ContextIdStrategy, let me do that and get back to you.

And maybe I should start with your test first :)

@vizio360
Copy link
Contributor

@micalevisk

Ok, cloned the repo, ran npm ci and then ran the app and the request.sh script and this is what I get

> $ ./request.sh test                                                                                                                             ⬡ 16.13.2 [±with-10809 ✓]
{"is_req_defined":true}%

that is without your patch applied and nestjs core 9.2.1, so it seems to work as expected without changing anything and even without my changes in the other PR...

Am I doing something wrong?

@micalevisk
Copy link
Member Author

@vizio360 did you use the branch main? so git clone -b main https://gitlab.com/micalevisk/nestjs-bug-pr-10793

@vizio360
Copy link
Contributor

vizio360 commented Jan 13, 2023

@vizio360 did you use the branch main? so git clone -b main https://gitlab.com/micalevisk/nestjs-bug-pr-10793

Just tested it with main and it seems to work. But the branch of your repo should not really matter as nestjs is installed as an npm.

simone.vicentini@Simones-MacBook-Pro ~/dev/repos/vizio360/nestjs-bug-pr-10793-main                                                                                [8:18:55]
> $ ./request.sh test                                                                                                                                   ⬡ 16.13.2 [±main ✓]
{"is_req_defined":true}%

@micalevisk
Copy link
Member Author

micalevisk commented Jan 13, 2023

@vizio360 the branch do matter as one has a patch that will be applied after install while the other doesn't.

git clone -b main https://gitlab.com/micalevisk/nestjs-bug-pr-10793
cd nestjs-bug-pr-10793
npm ci # even using npm i will reproduce the same
npm start

./request.sh foo
{"is_req_defined":false}

this is what I got on linux rn. Pretty weird 🤔

@vizio360
Copy link
Contributor

vizio360 commented Jan 13, 2023

@vizio360 the branch do matter as one has a patch that will be applied after install while the other doesn't.

git clone -b main https://gitlab.com/micalevisk/nestjs-bug-pr-10793
cd nestjs-bug-pr-10793
npm ci # even using npm i will reproduce the same
npm start

./request.sh foo
{"is_req_defined":false}

this is what I got on linux rn. Pretty weird 🤔

Oh ok, did not know it would automagically apply the patch (never used that before).

And sorry I've been switching context too many times and I see what I have done wrong... I was running the patched nestjs app from the other repo and the request script from the main repo. Apologies.

Doing it again now.

@vizio360
Copy link
Contributor

@micalevisk yeap same result.

simone.vicentini@Simones-MacBook-Pro ~/dev/repos/vizio360/nestjs-bug-pr-10793-main                                                                               [11:40:24]
> $ ./request.sh test                                                                                                                                   ⬡ 16.13.2 [±main ✓]
{"is_req_defined":false}%

Will properly look into it asap.

@vizio360
Copy link
Contributor

vizio360 commented Jan 13, 2023

I did some digging and I think I know what the problem is. I do have a solution but I need to test it further.

The issue seems to be in the RouterExplorer

contextId.getParent ? contextId.payload : request,

If the ContextIdStrategy::attach method returns a function ContextIdResolverFn and not an object ContextIdResolver then the payload on the context is not set. See ContextIdFactory::getByRequest :

    const contextId = createContextId();
    const resolverObjectOrFunction = this.strategy.attach(contextId, request);
    if (this.isContextIdResolverWithPayload(resolverObjectOrFunction)) {
      contextId.getParent = resolverObjectOrFunction.resolve;
      contextId.payload = resolverObjectOrFunction.payload;
    } else {
      contextId.getParent = resolverObjectOrFunction; //Here the payload is not set
    }
    return contextId;

But then in the RouterExplorer::getContextId method, it checks if the context.getParent exists and if so it passes the context.payload object to the registerRequestProvider function, but that payload is empty.

The fix I tried was to set the payload in the ContextIdFactory::getByRequest method to the request object, like so:

    const contextId = createContextId();
    const resolverObjectOrFunction = this.strategy.attach(contextId, request);
    if (this.isContextIdResolverWithPayload(resolverObjectOrFunction)) {
      contextId.getParent = resolverObjectOrFunction.resolve;
      contextId.payload = resolverObjectOrFunction.payload;
    } else {
      contextId.getParent = resolverObjectOrFunction; 
      contextId.payload = request //<-- HERE
    }
    return contextId;

But I need to run all the tests to make sure this will not break other things. Plus the same logic as per RouterExplorer is in MiddlewareModule and ListenersController.

@micalevisk
Copy link
Member Author

@vizio360 yeah that's was my first solution but see: #10793 (comment)

@vizio360
Copy link
Contributor

@micalevisk PR is ok, it does solve the issue.

@micalevisk micalevisk force-pushed the fix/durable-payload-regression branch from 637ceed to f396dc1 Compare January 27, 2023 16:08
@kamilmysliwiec kamilmysliwiec merged commit 6d88e3c into nestjs:master Feb 1, 2023
@kamilmysliwiec
Copy link
Member

lgtm

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.

4 participants