方案
我在Ubuntu OS中有永久模式运行的多个NodeJS脚本。其中一个文件( start.js )通过将其绑定到指定端口来导入启动ZMQ发布者的文件。当我分别以永久模式启动此 start.js 文件时,它会绑定并启动发布者,并且我能够通过连接到此端口的ZMQ订阅者获取此发布者发布的数据。 / p>
我通过检查exit,SIGINT和SIGUSR事件来优雅地关闭发布者。
每当我使用forever restart
单独重新启动此 start.js 文件时,发布者就会成功绑定并启动。如果我手动停止它(使用forever stop
)并使用forever start
再次启动它也可以正常工作[也适用于我手动停止的情况(使用forever stopall
)并永远启动它脚本一个接一个]。
注意:所有永久停止和重启命令都使用CLI选项运行--killSignal = SIGINT。
问题
但是当我forever restartall --killSignal=SIGINT
时,发布者未能绑定。它说该地址已被使用(我已使用netstat
检查了该地址,并且该端口没有tcp套接字)。当我停止所有脚本并逐个启动它时,它会正常绑定并成功启动。
我已经检查过这些kill信号是由发布者脚本捕获的,并在退出之前关闭了发布者套接字。
尝试失败:
降低了tcp套接字的TIME_WAIT状态。
启用TIME_WAIT套接字重用。
我认为tcp套接字需要时间才能释放 TIME_WAIT状态,并尝试在1000ms后绑定发布者 每次绑定失败,但脚本试图绑定和失败 每次尝试。
尝试永远使用SIGINT,SIGUSR1 kill重新启动所有脚本 发出信号并在绑定发布者的脚本中处理它们 插座。
这就是我在发布商处理SIG *事件的方式:
process.stdin.resume();
function exitHandler(options, err){
if (options.cleanup) console.log('pub-clean');
if (err) console.log("pub--" + err.stack);
if (options.exit){
socket.close();
console.log("Publisher Closed")
process.exit();
}
}
process.on('exit', exitHandler.bind(null,{cleanup:true}));
process.on('SIGINT', exitHandler.bind(null, {exit:true}));
process.on('uncaughtException', exitHandler.bind(null,{exit:true}));
process.on('SIGUSR2', exitHandler.bind(null, {exit:true}));
process.on('SIGTERM', exitHandler.bind(null, {exit:true}));
为什么永远重启所有脚本导致发布者脚本无法绑定?
可以做些什么来使发布商脚本永远重新启动时绑定?
答案 0 :(得分:0)
正如上面的评论中所讨论的,ZeroMQ资源的真正优雅版本通过系统级 SIG*
完成/ *KILL
,但执行ZeroMQ建议的优雅释放步骤。
到目前为止发布时,你在代码中根本不这样做,因此ZeroMQ资源可能并且很可能仍然悬而未决(至少I / O线程似乎)。
检查(尚未发布)设置中使用的ZeroMQ套接字设置(设置阶段使用的 .setsockopt()
调用)并添加:
.close()
(无论是否使用).close()
Context
实例 .term()
这被认为是所有(内部处理的)资源的保证ZeroMQ优雅释放。
优雅的释放
void msLIB.deinit() {
aComment.ADD( "msLIB.INFO: msLIB.deinit() TracePOINT.<BoPROC>|", False );
// --------------------------------------------------------------------------------------<THANKS>
// DO NOT EDIT: the below IS TRULY NEEDED or else one might get some nice memory leaks!
// ------------ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// -----------------------------------------------------------------------
// ZMQ-IMPERATIVE ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// _______________________________________________________________________ msMOD: ZMQ_Safe&CleanCODE_IMPERATIVE
zmq_setsockopt( zmqSpeaker, ZMQ_LINGER, 0 ); // no Sending QUEUE .... on ZMQ_PUBLISHER end
zmq_close( zmqSpeaker ); // Protect against memory leaks on shutdown.
aComment.ADD( "<1>", False );
aComment.ADD( " [[[ZMQ]]]<speaker_socket>.set( ZMQ_LINGER ) / .close()-ed ", True );
zmq_setsockopt( zmqListener, ZMQ_LINGER, 0 ); // aKBD.PUB
zmq_close( zmqListener ); // Protect against memory leaks on shutdown.
aComment.ADD( "<2>", False );
aComment.ADD( " [[[ZMQ]]]<listener_socket>.set( ZMQ_LINGER ) / .close()-ed ", True );
zmq_term( zmqContext ); // Protect against memory leaks on shutdown.
aComment.ADD( "<3>", False );
aComment.ADD( " [[[ZMQ]]]<context>.term()-ed ", True );
// _______________________________________________________________________ msMOD: ZMQ_Safe&CleanCODE_IMPERATIVE
// ------------
// DO NOT EDIT: the above IS TRULY NEEDED or else one might get some nice memory leaks!
// --------------------------------------------------------------------------------------<THANKS>
aComment.ADD( "|<EoPROC>", False );
msLIB.aSnapshot.MAKE();
aComment.ADD( "|aSnapshot.MAKE()-<DONE>", True );
return;
}
可以扩展架构,以便包含一个自己的软信令代码,用于所有需要处理得更软的情况,而不是通过 SIGKILL
等
和