【问题标题】:How to handle connection timeout in ZeroMQ.js properly?如何正确处理 ZeroMQ.js 中的连接超时?
【发布时间】:2019-11-25 10:08:21
【问题描述】:

考虑一个具有少量进程的 Node.js 应用程序:

  • 位于内存中并像 Web 服务器一样工作的单个主进程;
  • 系统用户的命令,可以通过 CLI 运行并在完成后退出。

我想在主进程和 CLI 进程之间实现类似 IPC 的东西,似乎 ZeroMQ bindings for Node.js 是一个非常好的候选者。我选择了6.0.0-beta.4 版本:

6.0.0 版(测试版)具有全新的 API,可解决许多基本问题,建议用于新项目。

使用Request/Reply 我能够实现我想要的:CLI 进程通知主进程一些发生的事件(并可选择接收一些数据作为响应)并继续执行。我现在遇到的一个问题是,如果主进程关闭(不可用),我的 CLI 进程就会挂起。如果无法建立到套接字的连接,该命令仍然必须执行并退出,而不通知主进程。

这是我的 CLI 以异步方法运行的简化代码 sn-p:

const { Request } = require('zeromq');

async function notify() {
  let parsedResponse;
  try {
    const message = { event: 'hello world' };
    const socket = new Request({ connectTimeout: 500 });
    socket.connect('tcp://127.0.0.1:33332');
    await socket.send(JSON.stringify(message));
    const response = await socket.receive();
    parsedResponse = JSON.parse(response.toString());
  }
  catch (e) {
    console.error(e);
  }
  return parsedResponse;
}

(async() => {
  const response = await notify();
  if (response) {
    console.log(response);
  }
  else {
    console.log('Nothing is received.');
  }
})();

我设置了connectTimeout 选项,但不知道如何使用它。文档状态:

设置在connect()系统调用超时之前等待多长时间。 connect() 系统调用通常需要很长时间才能返回超时错误。设置此选项允许库以更早的时间间隔使调用超时。

查看connect 一看就知道它不是异步的:

连接到给定远程地址的套接字并立即返回。连接将在后台异步进行。

好的,可能send 套接字的方法将等待连接建立并拒绝连接超时的承诺......但那里没有任何反应。 send 方法被执行并且代码停留在解析receive。它正在等待来自永远不会到来的主进程的回复。所以主要问题是:“如何使用connectTimeout 选项来处理套接字的连接超时?” 我发现an answer 与C++ 相关的类似问题,但它实际上并没有回答这个问题(或我无法理解)。不敢相信这个选项没用,而且它被添加到 API 中是为了让任何人都无法使用它。

我也会对某种解决方法感到满意,并找到了receiveTimeout 选项。将套接字创建更改为

const socket = new Request({ receiveTimeout: 500 });

导致receive 方法中的拒绝和以下输出:

{ [Error: Socket temporarily unavailable] errno: 11, code: 'EAGAIN' }
Nothing is received.

执行了源代码,但在这种情况下进程没有退出。似乎有些资源很忙,没有被释放。当主进程上线时,一切正常,进程退出,我在输出中有以下回复:

{ status: 'success' }

所以另一个问题是:“如何在拒绝receive 方法和receiveTimeout 时优雅地退出进程?”。在这里打电话process.exit() 不是一个选项!

附:我的环境是:

  • 库本图 18.04.1;
  • 节点 10.15.0;
  • ZeroMQ 绑定以这种方式安装:

    $ yarn add zeromq@6.0.0-beta.4 --zmq-shared
    

【问题讨论】:

    标签: node.js zeromq


    【解决方案1】:

    ZeroMQ 将套接字 connection 机制与消息 delivery 分离。正如文档所述,connectTimeout 仅影响connect() 系统调用的超时,不影响发送/接收消息的超时。

    例如:

    const zmq = require("zeromq")
    
    async function run() {
      const socket = new zmq.Dealer({connectTimeout: 2000})
      socket.events.on("connect:retry", event => {
        console.log(new Date(), event.type)
      })
    
      socket.connect("tcp://example.com:12345")
    }
    
    run()
    
    

    connect:retry 事件每约 2 秒发生一次:

    > node test.js
    2019-11-25T13:35:53.375Z connect:retry
    2019-11-25T13:35:55.536Z connect:retry
    2019-11-25T13:35:57.719Z connect:retry
    

    如果我们将connectTimeout 更改为200,那么您可以看到该事件将更频繁地发生。超时并不是影响事件之间延迟的唯一因素,但应该清楚的是它发生得更快。

    > node test.js
    2019-11-25T13:36:05.271Z connect:retry
    2019-11-25T13:36:05.531Z connect:retry
    2019-11-25T13:36:05.810Z connect:retry
    

    希望这能澄清connectTimeout的作用。

    【讨论】:

    • 感谢您阐明connectTimeout 的含义,但由于本地连接到tcp://localhost:12345tcp://127.0.0.1:12345 的某些原因,您的代码sn-p 对我不起作用。
    • 对不起...一切正常!我忘了停止主进程,所以发生了connect 事件而不是connect:retry。这很有帮助!
    • 总而言之,我留下一个与receiveTimeout 选项相关的reference to Github comment。为了优雅地处理receiveTimeout 拒绝,应为Request 实例使用以下选项:{ linger: 0 }{ immediate: true, sendTimeout: 500, receiveTimeout: 500 }
    猜你喜欢
    • 1970-01-01
    • 2018-05-27
    • 2020-08-24
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多