【问题标题】:Introducing delay between messages引入消息之间的延迟
【发布时间】:2021-04-28 13:45:18
【问题描述】:

我使用 Node.js。我有一个 MQTT 消息事件处理程序
index.js

client.on('message', function (topic, message) {
  // calls another function
  my_function(topic,message);
})

在接收消息时调用另一个函数my_function

async function my_function(topic,message) {
   const value = await dataFromPLC();
///processes the value together with message
}

使用exports.dataFromPLC = dataFromPLC从另一个文件导出并导入我的主函数的函数dataFromPLC如下所示
PLCfunctions.js

let client = new S7Client(plcSettings);
client.on('error', console.error);
 
async function dataFromPLC (){
  try {
    await client.connect();
  } catch (err){
    console.error(err);
  }
 
  try {
    // Read DB
    const res = await client.readDB(dbNr, dbVars);
    return res;
  } catch (err) {
    console.error(err);
  } finally {
    client.disconnect();
  }
}

当我收到一条 MQTT 消息或消息之间有足够的延迟时没有问题。但是,当我收到两条 MQTT 消息时,它们都调用my_function,随后调用dataFromPLC,两者之间没有太多延迟。我收到一条错误消息,因为在第二条消息尝试再次使用连接之前,PLC 连接没有足够的时间关闭。我查看了不同的选项,但不太确定如何解决问题。请问我能得到一些帮助吗?

【问题讨论】:

  • 您是否在每次收到消息时都连接到数据库并从数据库断开连接?这是一个好习惯吗?我总是在开始时打开一个连接,仅此而已。有一次await client.connect() 在脚本一开始就完成了。这需要几秒钟,但只有一次。
  • 我应该更清楚。它通过 TCP/IP 连接到 Siemens S7 PLC。由于我不经常收到 MQTT 消息(一天不超过 10 条),我认为保持 PLC 连接打开是一种浪费。另外我不太确定当PLC在晚上关闭并在第二天启动时它是否会自动重新连接。所以我认为这是一种安全的方式。它会解决下一个函数调用在第一个完成之前尝试从 PLC 读取数据的问题吗?
  • 确实啊,这和我想的完全不一样。我什至现在都不知道什么是西门子 S7 PLC :)
  • 您需要所有消息还是只需要每隔 x 时间发送一次消息?如果您需要消息,例如 200 毫秒,您可以解除消息处理程序的抖动并忽略其间的一些事件,这样您就可以每 200 毫秒不断收到至少 1 条消息(这适用于发送或接收),请查找 debounce,在这种情况下,这是一个有用的概念。
  • 谢谢@Sebastián Espinosa。但是所有的信息都是独一无二的,我需要记录所有的信息。这些消息仅在更改时生成。

标签: javascript node.js mqtt


【解决方案1】:

您必须设置一个消息队列,以便onMessage 仅将输入放入队列并将其处理推迟到以后。例如,您可以使用 then 作为入队操作将队列设为 Promise。这样可以保证在所有之前的处理完成之前不会开始处理。

这是一个小演示,点击按钮模拟传入消息:

let QUEUE = Promise.resolve()

function onMessage(msg) {
    console.log('GOT MESSAGE', msg)
    QUEUE = QUEUE.then(() => process(msg))
}

let pause = n => new Promise(r => setTimeout(r, n));

async function process(msg) {
    console.log('BEGIN', msg)
    await pause(200); console.log('busy', msg)
    await pause(200); console.log('busy', msg)
    await pause(200); console.log('busy', msg)
    await pause(200); console.log('busy', msg)
    await pause(200); console.log('busy', msg)
    console.log('END', msg)
}

msg = 0
document.querySelector('button').addEventListener('click', () => onMessage(++msg))
<button>message</button>

【讨论】:

  • 谢谢格罗格。我试过你的建议。它似乎不起作用。我更新了我的问题
  • 您的回答是正确的。谢谢@georg。在函数中声明一个没有let 的变量是一个愚蠢的错误。我赞成你的回答。
  • @SinuSen 如果答案是正确的,别忘了也选择它作为答案——它对未来的读者也有帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-28
  • 2018-10-11
  • 1970-01-01
相关资源
最近更新 更多