如何正确处理 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:12345
或tcp://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:连接超时