Javascript web3 websocket连接阻止节点进程退出
我有一个创建web3 websocket连接的node js进程,如下所示:Javascript web3 websocket连接阻止节点进程退出,javascript,websocket,ethereum,solidity,web3,Javascript,Websocket,Ethereum,Solidity,Web3,我有一个创建web3 websocket连接的node js进程,如下所示: web3 = new Web3('ws://localhost:7545') 当进程完成时(我向它发送一个SIGTERM),它不会退出,而是永远挂起,没有控制台输出 我在SIGINT和SIGTERM上注册了一个监听器,以观察进程在进程中有哪些未完成的句柄。\u getActiveRequests()和进程。\u getActiveHandles(),我看到了以下内容: Socket { connecting
web3 = new Web3('ws://localhost:7545')
当进程完成时(我向它发送一个SIGTERM),它不会退出,而是永远挂起,没有控制台输出
我在SIGINT和SIGTERM上注册了一个监听器,以观察进程在进程中有哪些未完成的句柄。\u getActiveRequests()
和进程。\u getActiveHandles()
,我看到了以下内容:
Socket {
connecting: false,
_hadError: false,
_handle:
TCP {
reading: true,
owner: [Circular],
onread: [Function: onread],
onconnection: null,
writeQueueSize: 0 },
<snip>
_peername: { address: '127.0.0.1', family: 'IPv4', port: 7545 },
<snip>
}
看起来web3打开了一个套接字,这很有意义,因为我从未告诉它关闭连接。通过查看文档和谷歌搜索,web3对象似乎没有关闭或结束方法
在上面的stop
中手动关闭套接字可使进程成功退出:
web3.currentProvider.connection.close()
有人有更优雅或官方认可的解决方案吗?我觉得很有趣,您必须手动执行此操作,而不是让对象在进程结束时自行销毁。其他客户端似乎会自动执行此操作,而不会明确告诉他们关闭连接。也许告诉您的节点进程创建的所有客户端在关机时关闭它们的句柄/连接会更干净,但对我来说,这是出乎意料的。在您的节点进程结束时,只需调用:
web3.currentProvider.connection.close()
我觉得很有趣的是,您必须手动执行此操作,而不是让对象在进程结束时自行销毁
这感觉很有趣,因为与异步编程相比,您可能接触到了更多的同步编程。考虑下面的代码
fs = require('fs')
data = fs.readFileSync('file.txt', 'utf-8');
console.log("Read data", data)
当您在上面运行时,您将获得输出
$ node sync.js
Read data Hello World
这是一个同步代码。现在考虑相同版本的异步版本
fs = require('fs')
data = fs.readFile('file.txt', 'utf-8', function(err, data) {
console.log("Got data back from file", data)
});
console.log("Read data", data);
当您运行时,您将获得以下输出
$ node async.js
Read data undefined
Got data back from file Hello World
现在,如果您认为作为一个同步程序员,程序应该在最后一个console.log(“读取数据”,data)处结束代码>,但您得到的是随后打印的另一条语句。这感觉好笑吗?让我们向流程中添加一个exit语句
fs = require('fs')
data = fs.readFile('file.txt', 'utf-8', function(err, data) {
console.log("Got data back from file", data)
});
console.log("Read data", data);
process.exit(0)
现在,当您运行程序时,它将在最后一条语句结束
$ node async.js
Read data undefined
但该文件实际上并没有被读取。为什么?因为您从未给JavaScript引擎时间来执行挂起的回调。理想情况下,当一个进程没有剩余的工作(没有挂起的回调、函数调用等)时,它会自动完成。这就是异步世界的工作方式。有一些好的线索和文章,你应该看看
因此,在异步世界中,您需要告诉进程退出,或者在没有挂起的任务时它将自动退出(您知道如何检查-process.\u getActiveRequests()
和process.\u getActiveHandles()
)由于和的实现,JavaScript web3模块的提供程序API最近经历了一些重大变化
根据,它看起来像是web3.currentProvider.disconnect()
应该可以工作。此方法还接受可选的code
和reason
参数,如中所述
重要提示:您会注意到我引用了上面的源代码,而不是文档。这是因为目前,disconnect
方法不被认为是公共API的一部分。如果您在代码中使用它,您应该确保为它添加一个测试用例,因为它可能随时中断据我所见,WebSocketProvider.disconnect
是在web3@1.0.0-beta.38
至今仍存在于最新版本中,即web3@1.0.0-beta.55
。考虑到稳定的1.0.0版本即将推出,我认为从现在到web3@1.0.0
,但在内部API的结构方面没有任何限制
我已经与当前的维护人员Samuel Furter(又名GitHub上的nividia)详细讨论了如何公开内部提供者。我不完全同意他将其保留在内部的决定,但为他辩护,他是目前唯一的维护者,他一直忙于稳定1.0
分支上正在进行的长期工作
通过这些讨论,我目前的观点是,那些需要为WebSocket提供商提供稳定API的人应该自己编写一个与EIP-1193兼容的提供商,并将其发布在NPM上供其他人使用。为此,请遵循semver,并在您自己的公共API中包含类似的disconnect
方法。如果使用TypeScript
编写,则会获得额外的积分,因为这样可以将类成员显式声明为public
、protected
或private
如果您这样做,请注意EIP-1193仍处于草稿状态,因此您需要密切关注中的EIP-1193讨论,以了解可能发生的任何更改。当流程完成时,您所说的是什么意思?您的进程是一个侦听端口的HTTP服务器。它怎么知道应该停止监听?对不起,我不清楚这个过程是如何完成的。我正在向节点进程发送终止信号。express和mongo似乎在进程退出时自动关闭句柄,但web3没有。它在哪个系统上运行?你的流程有子流程吗?debian jessie。没有一个孩子在Docker容器内运行,尽管我认为这不重要。我想我不清楚自己的期望。我更新了这个问题,希望它更容易理解。我觉得有趣的不是事件循环是如何工作的,而是web3客户端没有监听进程退出和清理的事实。@AndyPang,这件事,你的期望是一个陷阱22。只有在没有挂起的内容时,您的进程才会退出。websocket
是一个连续的开放通道,假定它保持开放。在NodeJS中,事情不会自行关闭
$ node async.js
Read data undefined