question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Undefined dependencies and private fields in rabbitmq subscriber

See original GitHub issue

Hello everyone. ✋ I have one strange issue with RabbitSubscribe. There is module with the exchange consumer that handle files in base64 format. Module:

import { Module } from '@nestjs/common';
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
import { FileConsumer } from './file.consumer';
import { FILE_SERVICE } from './di.constants';
import { FileService } from './file.service';
import { rabbitExchangesConfig } from '../config/rabbitmq';

@Module({
  imports: [
    RabbitMQModule.forRoot(RabbitMQModule, {
      uri: rabbitExchangesConfig.fileSaver.uri,
      exchanges: [
        {
          type: 'fanout',
          name: rabbitExchangesConfig.fileSaver.exchange,
        },
      ],
    }),
  ],
  providers: [
    FileConsumer,
    {
      provide: FILE_SERVICE,
      useClass: FileService,
    },
  ],
})
export class FileModule {}

Consumer:

import { Inject, Injectable } from '@nestjs/common';
import { Nack, RabbitSubscribe } from '@golevelup/nestjs-rabbitmq';
import { LoggerFactory } from '@company/logger-winston';
import { FILE_SERVICE } from './di.constants';
import { IFileService } from './file.service';
import { rabbitExchangesConfig } from '../config/rabbitmq';
import { FileSaveData } from './types';
import { FileWasNotFoundError } from './errors';

@Injectable()
export class FileConsumer {
  private readonly logger = LoggerFactory.getLogger(FileConsumer.name);

  constructor(@Inject(FILE_SERVICE) private readonly fileService: IFileService) {}

  @RabbitSubscribe({
    exchange: rabbitExchangesConfig.fileSaver.exchange,
    queue: rabbitExchangesConfig.fileSaver.queue,
    routingKey: rabbitExchangesConfig.fileSaver.routingKey,
  })
  public async uploadFile(msg: FileSaveData): Promise<null | Nack> {
    if (!msg.fileId || !msg.rawData) {
      this.logger.error('Incoming message is broken', { msg });
      return new Nack(false);
    }
    this.logger.info(`Income new message: ${msg}`, { fileId: msg.fileId });
    try {
      await this.fileService.uploadFile(msg);
      return null;
    } catch (err) {
      this.logger.error('Failed processing data', err, { fileId: msg.fileId });
      switch (true) {
        case err instanceof FileWasNotFoundError:
          return new Nack(false);
        default:
          return new Nack(true);
      }
    }
  }
}

main.ts:

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import * as bodyParser from 'body-parser';
import { AppModule } from './app.module';
import { AppConfigService } from './config';
import { WinstonLogger } from './logger';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule, {
    // logger: false,
  });
  const appConfig = app.get<AppConfigService>('AppConfigService');
  const logger = new WinstonLogger('APP');
  app.useLogger(logger);
  app.useGlobalPipes(new ValidationPipe());

  app.setGlobalPrefix('api');
  app.use(bodyParser.json({ limit: '10mb' }));
  app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }));
  const options = new DocumentBuilder()
    .setTitle('Core service')
    .setDescription('Core API description')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api-doc', app, document);

  return app.listen(appConfig.port);
}
bootstrap();

I see in my logs that subscriber has connected to my exchange with set queue and routing key:

2021-03-15 21:11:30 [APP] info: Initializing RabbitMQ Handlers { env: 'local', server_env: 'local', pid: 308 }
2021-03-15 21:11:30 [APP] info: Registering rabbitmq handlers from FileConsumer { env: 'local', server_env: 'local', pid: 308 }
2021-03-15 21:11:30 [APP] info: FileConsumer.uploadFile {subscribe} -> rc-oc.file_saver.spool.exchange::rc-oc.file_saver::rc-oc.file_saver.spool { env: 'local', server_env: 'local', pid: 308 }
2021-03-15 21:11:30 [APP] info: Successfully connected a RabbitMQ channel { env: 'local', server_env: 'local', pid: 308 }
2021-03-15 21:11:30 [APP] info: Nest application successfully started { env: 'local', server_env: 'local', pid: 308 }

But I have a problem with accessing to my private fields and injected dependencies because after receiving message from exchange my logger and injected service are undefined. I’ve tested an invocation of constructor of FileConsumer, and saw that It wasn’t called before handling message from exchange. 🤯

I also have a http controllers in another modules and don’t have any problems with injection. Can anyone help me? It’s really strange bug. 🤔

Version of @golevelup/nestjs-rabbitmq is 1.16.0.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:4
  • Comments:10

github_iconTop GitHub Comments

9reactions
WonderPandacommented, Mar 27, 2021

@Scrib3r I can see how Unit of Work would be a desirable pattern to be able to implement when processing messages from RabbitMQ. I’m not sure how much work is involved with being able to leverage Scope.Request outside the context of HTTP or if it is even possible but I will take a look and see what is possible

4reactions
silentroachcommented, Jun 16, 2021

+1 for request scoped consumers like in nest

Read more comments on GitHub >

github_iconTop Results From Across the Web

Problems with RabbitMQ and NestJS. I can't publish a ...
Basically I have handling messages working fine but I can't send any, I just get a "Cannot read properties of undefined (reading 'isConnected')" ......
Read more >
AMQP 0-9-1 Complete Reference Guide - RabbitMQ
This method sends the client's connection tuning parameters to the server. Certain fields are negotiated, others provide capability information.
Read more >
Custom providers | NestJS - A progressive Node.js framework
ts , CatsController declares a dependency on the CatsService token with constructor injection: constructor(private catsService: CatsService). In app.module.
Read more >
amqp091-go - Go Packages
Package amqp091 is an AMQP 0.9.1 client with RabbitMQ extensions. ... with positional parameters mapping to named protocol message fields.
Read more >
Spring Framework Reference Documentation
Spring Dependencies and Depending on Spring; Maven Dependency Management ... Setting and getting basic and nested properties; 9.4.2. ... AMQP; 28.8.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found