nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
67.57k stars 7.61k forks source link

Microservices @EventPattern use injected factory and loose factory data or context #4533

Closed brasycad closed 4 years ago

brasycad commented 4 years ago

Bug Report

Current behavior

Within the 'handleWaitingHash' function, the EventsServices service has a public field where connected users are stored. Throughout the application, EventsServices stores that information seamlessly and shares it in Singleton mode. But specifically, inside 'EventsPattern', it's like a new and empty instance.

import { Post, Controller, Req, Res, UseGuards, Body, UseInterceptors, CacheInterceptor } from '@nestjs/common';
import { EventsServices } from '../events-module'
@Controller()
export class EventsController {
    constructor(private EventsServices: EventsServices) {
    }
    @EventPattern('WAITING_HASH')
    async handleWaitingHash(data:any) {
        console.log(this.EventsServices.threads.length) // give 0, must give some amount
        return await this.EventsServices.searchingHash()
    }
}

- Nest version: 7.0.1
- Node version: v13.5.0
- Platform:   Centos 7
kamilmysliwiec commented 4 years ago

Please provide a minimum reproduction repository.

brasycad commented 4 years ago
import { Post, Controller, Req, Res, UseGuards, Body, UseInterceptors, CacheInterceptor } from '@nestjs/common';
import { IBet, IDraw } from '../main-module/draws.interfaces'
import { EventsServices } from '../events-module'
import * as _ from 'lodash'
import { EventPattern, MessagePattern, Ctx, Payload } from '@nestjs/microservices'

@Controller()
export class EventsController {
    constructor(private EventsServices: EventsServices) {
    }
    @EventPattern('WAITING_HASH')
    async handleUserCreated(@Payload() data: number[], @Ctx() context: any) {
        console.log('Num threads', this.EventsServices.Threads.threads.length) // Num threads 0
        return await this.EventsServices.searchingHash()
    }
    @UseGuards(AuthGuard('jwt'))
    @Post('/fetchEvaluatedBets')
    async fetchEvaluatedBets(@Req() req, @Res() res, @Body() params) {
        console.log('Num threads', this.EventsServices.Threads.threads.length) // Num threads 120
        res.send(await this.Services.fetchEvaluatedBets(params))
    }
    @UseGuards(AuthGuard('jwt'))
    @Post('/fetchWinnersBets')
    async fetchWinnersBets(@Req() req, @Res() res, @Body() params) {
        console.log('Num threads', this.EventsServices.Threads.threads.length) // Num threads 120
        res.send(await this.Services.fetchWinnersBets(params))
    }
}

I'm sorry I wasn't clearer. I'm exposing you to a more extensive controller so that I can understand what the problem is. The behavior of the 'EventsServices' factory within the same controller is different. In any function like 'fetchEvaluatedBets' or 'fetchWinnersBets' if we want to see how many threads are currently subscribed, 'this.EventsServices.Threads.length' gives us this information.

The problem is that inside '@EventPattern' the value it gives is 0. It's like it's another factory he's accessing.

Thanks. And congratulations for your wonderful Library!!

kamilmysliwiec commented 4 years ago

Unfortunately, we can't help without a minimum reproduction repository. :(

brasycad commented 4 years ago

I'm going to try to simplify the example, so that we can get to the problem more simply. The same controller with an @EventPattern and @Get functions. We put a counter initialized to 0 The reasonable thing would be that every time one of these two possible functions is called, this counter is increased by one.

import { Post, Get, Controller, Req, Res,  } from '@nestjs/common';
import * as _ from 'lodash'
import { EventPattern } from '@nestjs/microservices'

@Controller()
export class EventsController {
    private counter = 0
    constructor() {
    }
    @EventPattern('WAITING_HASH')
    async handleUserCreated(data) {
        console.log('EventPattern counter', ++this.counter)
    }
    @Get('/test')
    async test(@Res() res, @Body() params) {
        console.log('test counter', ++this.counter)
    }
}

Actual behaviour: EventPattern counter 1 EventPattern counter 2 EventPattern counter 3 test counter 1 test counter 2 EventPattern counter 4 test counter 3 .... As you can see, the same variable from the same controller has different values depending on which method you call it I hope this example will be clear enough Thanks

johnbiundo commented 4 years ago

Good that you reduced this. Could you please create a repository with this and share it. Thanks.

gperdomor commented 4 years ago

@brasycad I can't reproduce your problem...

Screen Shot 2020-04-09 at 16 52 11
kamilmysliwiec commented 4 years ago

I can't reproduce your issue either. Please, next time provide a minimum reproduction repository.