NestJS MQTT微服务有效的@MessagePattern是什么?

时间:2018-10-24 08:18:25

标签: node.js typescript microservices mqtt nestjs

我正在尝试根据the docs使用NestJS设置MQTT微服务。

我已经使用Docker启动了可工作的Mosquitto Broker,并使用各种MQTT客户端验证了其可操作性。现在,当我启动NestJS服务时,它似乎已正确连接(mqqt.fx显示了新客户端),但是我无法在控制器中接收任何消息。 这是我的引导程序,就像在文档中一样:

main.ts

async function bootstrap() {
    const app = await NestFactory.createMicroservice(AppModule, {
        transport: Transport.MQTT,
        options: {
            host: 'localhost',
            port: 1883,
            protocol: 'tcp'
        }
    });
    app.listen(() => console.log('Microservice is listening'));
}
bootstrap();

app.controller.ts

@Controller()
export class AppController {

    @MessagePattern('mytopic') // tried {cmd:'mytopic'} or {topic:'mytopic'}
    root(msg: Buffer) {
        console.log('received: ', msg)
    }
}

我是否错误地使用了消息模式装饰器,或者我的概念是否对NestJS MQTT微服务应该做什么有误?我认为它可能会订阅我传递给装饰器的主题。我唯一的其他信息来源是相应的unit tests

5 个答案:

答案 0 :(得分:2)

文档不是很清楚,但是对于mqtt来说,如果您拥有@MessagePattern('mytopic'),则可以在主题mytopic_ack上发布命令,并且您会在mytopic_res上得到答复。我仍在尝试找出如何从服务发布到mqtt经纪人的方法。

请参见https://github.com/nestjs/nest/blob/e019afa472c432ffe9e7330dc786539221652412/packages/microservices/server/server-mqtt.ts#L99

  public getAckQueueName(pattern: string): string {
    return `${pattern}_ack`;
  }

  public getResQueueName(pattern: string): string {
    return `${pattern}_res`;
  }

答案 1 :(得分:2)

nest.js模式处理程序

在nest.js方面,我们具有以下模式处理程序:

@MessagePattern('sum')
sum(data: number[]): number {
  return data.reduce((a, b) => a + b, 0);
}

正如@Alexandre所解释的那样,这实际上会监听sum_ack


Non-nest.js客户端

非nest.js客户端可能如下所示(只需另存为client.js,运行npm install mqtt并使用node client.js运行程序):

var mqtt = require('mqtt')
var client  = mqtt.connect('mqtt://localhost:1883')

client.on('connect', function () {
  client.subscribe('sum_res', function (err) {
    if (!err) {
      client.publish('sum_ack', '{"data": [2, 3]}');
    }
  })
})

client.on('message', function (topic, message) {
  console.log(message.toString())
  client.end()
})

它发送有关主题sum_ack的消息,并收听sum_res上的消息。当它在sum_res上收到消息时,它将记录该消息并结束程序。 nest.js希望消息格式为{data: myData},然后调用参数处理程序sum(myData)

// Log:
{"err":null,"response":5} // This is the response from sum()
{"isDisposed":true} // Internal "complete event" (according to unit test)

当然,这不是很方便...


nest.js客户端

这是因为它打算与另一个nest.js客户端而不是普通的mqtt客户端一起使用。 nest.js客户端将所有内部逻辑抽象出来。请参阅this answer,其中描述了redis的客户端(mqtt仅需要更改两行)。

async onModuleInit() {
  await this.client.connect();
  // no 'sum_ack' or {data: [0, 2, 3]} needed
  this.client.send('sum', [0, 2, 3]).toPromise();
}

答案 2 :(得分:0)

我今天在与MQTT战斗,这对我有所帮助,但是我遇到了更多问题,下面您可以看到我的发现:

配置代理URL的方式错误

在我使用非本地MQTT服务器的情况下,我以此开始:

  const app = await NestFactory.createMicroservice(AppModule, {
    transport: Transport.MQTT,
    options: {
      host: 'test.mosquitto.org',
      port: 1883,
      protocol: 'tcp',
    },
  });
  await app.listenAsync();

但是,就像您可以在constructor of ServerMqtt中阅读一样,他们仅使用url选项(如果未提供,则回退到'mqtt://localhost:1883'。虽然我没有本地MQTT,但它永远不会解析{{ 1}},仅在connect上解决,并且也不会运行任何处理程序。

当我调整代码以使用app.listenAsync()选项时,它开始工作。

url

邮件需要 const app = await NestFactory.createMicroservice(AppModule, { transport: Transport.MQTT, options: { url: 'mqtt://test.mosquitto.org:1883', }, }); await app.listenAsync(); 属性

第二个非常奇怪的问题是,当我使用@KimKern的 Non-nest.js客户端脚本时,我必须注册两个MessagePatterns:idsum

sum_ack

当我使用 @MessagePattern('sum') sum(data: number[]): number { return data.reduce((a, b) => a + b, 0); } @MessagePattern('sum_ack') sumAck(data: number[]): number { return data.reduce((a, b) => a + b, 0); } 时,我发现后者正在运行,但仅当第一个存在时才运行。您可以使用mqtt cli工具将同一条消息推送到代理,以进行检查:

console.log

但是最大的问题是它没有回复(发布sum_res)

解决方案是在发送消息时也提供mqtt pub -t 'sum_ack' -h 'test.mosquitto.org' -m '{"data":[1,2]}'

id

然后我们可以删除'sum_ack'MessagePattern并仅保留以下代码:

mqtt pub -t 'sum_ack' -h 'test.mosquitto.org' -m '{"data":[1,2], "id":"any-id"}'

其原因隐藏在ServerMqtt的 @MessagePattern('sum') sum(data: number[]): number { return data.reduce((a, b) => a + b, 0); } 方法内,如果消息中没有publish,则该方法不会id来自处理程序的响应。

TL / DR 仅使用handleMessage选项指定消息代理的URL,并始终为消息提供url

我希望这可以节省一些时间。

黑客很开心!

答案 3 :(得分:0)

@Tanas 是对的。 Nestjs/Microservice 现在听你的 $[topic] 并回答 $[topic]/reply。后缀 _ack 和 _res 已弃用。

例如:

  @MessagePattern('helloWorld')
  getHello(): string {
    console.log("hello world")
    return this.appService.getHello();
  }

现在收听主题:helloWorld
立即回复主题 helloWorld/reply

关于 ID

应该还在有效负载中提供一个 id(参见@Hakier),Nestjs 将回复一个包含您的 id 的答案。 如果你没有任何id,仍然不会有任何回复,但仍然会触发相应的逻辑。

例如(使用上面的截图):
您的留言:

{"data":"foo","id":"bar"}

Nestjs 回复:

{"response":"Hello World!","isDisposed":true,"id":"bar"}

没有身份证:

您的留言:

{"data":"foo"} or {}

没有回复,但是终端中的Hello World

答案 4 :(得分:-1)

此奇怪的行为已在Nest 7.0中修复。您可以直接订阅主题,没有任何后缀。