ssut / nestjs-sqs

A project to make SQS easier to use within NestJS, with decorator-based handling and seamless NestJS-way integration.
MIT License
215 stars 53 forks source link

meta undefined #3

Closed hdiaz-nectia closed 3 years ago

hdiaz-nectia commented 3 years ago

Hi,

I'm trying to setup this package in my app module class like that:

const sqs = new AWS.SQS({
  apiVersion: '2012-11-05',
  credentials: new AWS.Credentials('xxxxx', 'xxxxx'),
  region: 'none',
});

@Module({
  imports: [
  SqsModule.registerAsync({
    useFactory: () => {
      return {
        consumers: [
          {
            name: 'my-queue',
            queueUrl: `${SQS_ENDPOINT}/queue/`, // SQS_ENDPOINT: 'http://localhost:9324'
            sqs, // instance of new AWS.SQS
            waitTimeSeconds: 1,
            batchSize: 3,
            terminateVisibilityTimeout: true,
            messageAttributeNames: ['All'],
          }
        ],
        producers: [],
      };
    },
  }),

but, when run my app thow next error:

[NestWinston] Warn 2020-12-9 17:09:04 [SqsService] No metadata found for: my-queue - {}
(node:22174) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'meta' of undefined

This is the line in sqs.service.js

const isBatchHandler = metadata.meta.batch === true;

I only need to consume messages from SQS and I'm using a elasticmq docker container to test:

docker run -p 9324:9324 -p 9325:9325 softwaremill/elasticmq
hdiaz-nectia commented 3 years ago

I solved, I needed to add my service class like provider in app.module.ts, the documentation doesn't tell this.

@Injectable()
export class AppMessageHandler {

  @SqsMessageHandler('my-queue', false)
  public async handleMessage(message: AWS.SQS.Message) {
    console.log(message);
  }

  @SqsConsumerEventHandler(
    /** name: */ 'my-queue',
    /** eventName: */ 'processing_error',
  )
  public onProcessingError(error: Error, message: AWS.SQS.Message) {
    // report errors here
    console.error(error);
    console.error(message);
  }
}
nickkang1 commented 3 years ago

After a lot of trial and error, I found that to avoid this error, you can't use process.env in the SqsMessageHandler decorator. It seems like nestjs-sqs instantiates the SQS listeners before process.env is available to the app.

Change @SqsMessageHandler(process.env.MY_SQS_TOPIC_NAME!) to @SqsMessageHandler('my-sqs-topic-name'). It looks like constants also work.

With this change, you should be able to use nestjs-sqs anywhere in your app.

MickL commented 2 years ago

I also get the error and cant figure out what its causing it. Maybe the actual cause of the error is something else:

TypeError: Cannot read properties of undefined (reading 'meta')

I already get this error when not having any controller, just by importing SqsModule.register(...). It also only appears for the consumers array, not for the producers array.

imports:     [
        SqsModule.register({
            consumers: [
                {
                    name:     config.get('myQueue.name'),
                    queueUrl: config.get('myQueue.url'),
                    sqs,
                }
            ],
        }),
    ],

@ssut do you have any idea?

MickL commented 2 years ago

I found the error! It comes when there is not @SqsMessageHandler found for the specified name. In my case I added the Injectable Service to controllers instead of providers.

@ssut I think the error message should be improved. Instead it could be something like "You registered a consumer 'xy' but no MessageHandler found for that name"

deenMuhammad commented 1 week ago

For anyone is struggling with the similar issue you can use process.env with dotenv in nestjs. Configure dotenv and then assign env.variable to a constant value like this:

const queueName = process.env.QUEUE_NAME;
@Injectable()
export class SqsService {
...
@SqsMessageHandler(queueName)
...
}

For more cases refer to this.