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

Posted

技术标签:

【中文标题】如何正确处理 ZeroMQ.js 中的连接超时?【英文标题】:How to handle connection timeout in ZeroMQ.js properly? 【发布时间】: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

【问题讨论】:

【参考方案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

以上是关于如何正确处理 ZeroMQ.js 中的连接超时?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确处理连接空闲超时错误

PHP中的Facebook Graph API出现不一致的错误 - 无法连接到graph.facebook.com端口443:连接超时

使用连接池处理活动记录超时的正确方法是啥?

从SecureCRT连接到虚拟机失败。提示连接超时。求解决办法。200分。

如何在Laravel中修复PDO sqlsrv连接超时?

如何设置远程连接到 postgresql 数据库的 jdbc 连接超时值?