Search code examples
node.jsdeploymentnestjsmqttpm2

MQTT + NestJS TypeError when running with NodeJS directly


NestJs + MQTT error when trying to host with PM2/NodeJS

I am trying to use a Controller with MessagePatterns in NestJs to handle messages on some MQTT topics. I am also using an NX monorepo. Everything works fine when I run:

yarn nx serve api

I am working on a deployment strategy, and when I compile my project using:

yarn nx run-many --t=build --configuration=production

Everything is compiling fine.

The issue comes in when I try to run the compiled project using

node ./dist/apps/api/main.js

This causes the following error-message

/home/user/Desktop/project/node_modules/mqtt/lib/client.js:701
  const resubscribe = obj.resubscribe
                          ^

TypeError: Cannot read properties of undefined (reading 'resubscribe')
    at MqttClient.subscribe (/home/user/Desktop/project/node_modules/mqtt/lib/client.js:701:27)
    at /home/user/Desktop/project/node_modules/@nestjs/microservices/server/server-mqtt.js:40:24
    at Array.forEach (<anonymous>)
    at ServerMqtt.bindEvents (/home/user/Desktop/project/node_modules/@nestjs/microservices/server/server-mqtt.js:38:28)
    at ServerMqtt.start (/home/user/Desktop/project/node_modules/@nestjs/microservices/server/server-mqtt.js:32:14)
    at ServerMqtt.listen (/home/user/Desktop/project/node_modules/@nestjs/microservices/server/server-mqtt.js:24:18)
    at /home/user/Desktop/project/node_modules/@nestjs/microservices/nest-microservice.js:107:25
    at new Promise (<anonymous>)
    at NestMicroservice.listen (/home/user/Desktop/project/node_modules/@nestjs/microservices/nest-microservice.js:106:16)

I have tried the following (with no success)

  • Different NodeJS versions (Currently on v18.16.0)
  • Different versions of the MQTT library
  • Commenting out certain parts of code:

Here is a snippet from my main.ts file:

const mqtt_app = await NestFactory.createMicroservice(AppModule, {
    transport: Transport.MQTT,
    options: {
        url: process.env.MQTT_URL,
        username: process.env.MQTT_USERNAME,
        password: process.env.MQTT_PASSWORD,
    },
});
mqtt_app.listen();

If I don't call mqtt_app.listen();, I don't have an issue, but that also means that nothing related to MQTT will work.

My mqtt.controller file:

import { Controller } from '@nestjs/common';
import { MessagePattern, Payload } from '@nestjs/microservices';

@Controller()
export class MqttController {
    @MessagePattern(process.env.MQTT_TOPIC_1)
    async mqtt_a(@Payload() data) {
        console.log(`Received ${data} on ${process.env.MQTT_TOPIC_1}`);
        return `Received ${data} on ${process.env.MQTT_TOPIC_1}}`
    };
    @MessagePattern(process.env.MQTT_TOPIC_2)
    async mqtt_b(@Payload() data) {
        console.log(`Received ${data} on ${process.env.MQTT_TOPIC_2}`);
        return `Received ${data} on ${process.env.MQTT_TOPIC_2}}`
    }
}

If I comment out the two @MmessagePattern()'s and functions mqtt_a and mqtt_b, everything seems to work fine. I suspect that when I run this using NodeJS directly, it tries to 'subscribe' to a topic before the microservice is running, or something simillar?

Maybe I am missing something very obvious, but I am out of ideas and any help regarding this will be greatly appreciated!


Solution

  • Problem solved!

    The issue was using .env for the messagepatterns

    @MessagePattern(process.env.MQTT_TOPIC_2)
    

    Fixed by rather doing

    @MessagePattern('topic')
    

    This only seems to be an issue when running the compiled code using NodeJS though, and for some reason using process.env.* works fine when running the project using NX / NestJS directly.