如何正确处理 ZeroMQ.js 中的连接超时?

How to handle connection timeout in ZeroMQ.js properly?

考虑一个 Node.js 进程很少的应用程序:

我想实现类似 IPC between main and CLI processes, and it seems that ZeroMQ bindings for Node.js 的东西是一个很好的选择。我选择了 6.0.0-beta.4 版本:

Version 6.0.0 (in beta) features a brand new API that solves many fundamental issues and is recommended for new projects.

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

这是我的 CLI 运行ning 在异步方法中的简化代码片段:

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 选项,但不知道如何使用它。文档状态:

Sets how long to wait before timing-out a connect() system call. The connect() system call normally takes a long time before it returns a time out error. Setting this option allows the library to time out the call at an earlier interval.

查看 connect 可以看出它不是异步的:

Connects to the socket at the given remote address and returns immediately. The connection will be made asynchronously in the background.

好的,套接字的 send 方法可能会等待连接建立并在连接超时时拒绝承诺...但那里什么也没有发生。 send 方法已执行,代码卡在解析 receive 处。它正在等待永远不会到来的主进程的回复。所以主要问题是: "How to use connectTimeout option to handle socket's connection timeout?" 我发现 与 C++ 相关的类似问题,但它实际上没有回答问题(或者我无法理解它)。不能相信这个选项是无用的并且它被添加到 API 以便没有人可以使用它。

我也很乐意提供某种解决方法,并找到了 receiveTimeout 选项。将套接字创建更改为

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

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

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

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

{ status: 'success' }

所以另一个问题是:"How to exit the process gracefully on rejecting receive method with receiveTimeout?"。在这里调用 process.exit() 不是一个选项!

P.S。我的环境是:

ZeroMQ 将套接字连接 机制与消息传递 分离。正如文档所述 connectTimeout 仅影响 connect() 系统调用的超时,不会影响 sending/receiving 消息的超时。

例如:

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 的影响。