我有一个node js进程,它创建了一个web 3 WebSocket连接,如下所示:
web3 = new Web3('ws://localhost:7545')
当进程完成时(我向它发送一个SIGTERM),它不会退出,而是永远挂起,没有控制台输出。
我在SIGINT和SIGTERM上注册了一个侦听器,以观察process._getActiveRequests()
和process._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>
}
为了完整起见,下面是侦听信号的代码:
async function stop() {
console.log('Shutting down...')
if (process.env.DEBUG) console.log(process._getActiveHandles())
process.exit(0)
}
process.on('SIGTERM', async () => {
console.log('Received SIGTERM')
await stop()
})
process.on('SIGINT', async () => {
console.log('Received SIGINT')
await stop()
})
看起来web 3打开了一个套接字,这是有道理的,因为我从来没有告诉它关闭连接。通过查看文档和谷歌搜索,它看起来不像有一个关闭或结束方法的web 3对象。
手动关闭上述stop
中的套接字,可以成功退出进程:
web3.currentProvider.connection.close()
有人有更优雅或官方认可的解决方案吗?我觉得很有趣的是,你必须手动完成这项工作,而不是让对象在进程结束时自行销毁。其他客户端似乎会自动完成这项工作,而不会明确告诉他们关闭连接。也许告诉所有由节点进程创建的客户端在关闭时关闭句柄/连接会更干净,但对我来说,这是意料之外。
3条答案
按热度按时间aiazj4mn1#
我觉得很有趣的是,你必须手动完成这一点,而不是让对象在进程结束时销毁自己
这感觉很有趣,因为与异步编程相比,您可能接触过更多的同步编程。
当你运行上面的程序时,你会得到输出
这是一个同步代码。现在考虑同一个
运行时,将得到以下输出
现在,如果您认为作为一个同步程序员,程序应该在最后一个
console.log("Read data", data);
处结束,但是您得到的是随后打印的另一条语句。现在,当您执行程式时,它会在最后一个陈述式结束。
但是文件实际上并没有被读取。为什么?因为你从来没有给JavaScript引擎时间来执行挂起的回调。理想情况下,当没有工作要做时(没有挂起的回调、函数调用等),进程会自动结束。这就是异步世界的工作方式。有一些很好的SO线程和文章你应该去看看
https://medium.freecodecamp.org/walking-inside-nodejs-event-loop-85caeca391a9
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
How to exit in Node.js
Why doesn't my Node.js process terminate once all listeners have been removed?
How does a node.js process know when to stop?
因此在异步环境中,您需要告诉进程退出,或者在没有挂起的任务时自动退出(您知道如何检查-
process._getActiveRequests()
和process._getActiveHandles()
)csbfibhn2#
由于EIP-1193和impending release of Web3 1.0.0的实现,JavaScript web 3模块的提供者API最近经历了一些实质性的变化。
根据代码,
web3.currentProvider.disconnect()
看起来应该可以工作。该方法还接受可选的code
和reason
参数,如the MDN reference docs forWebSocket.close(...)
中所述。**重要提示:你会注意到我引用了上面的源代码而不是文档。这是因为目前
disconnect
方法还不被认为是公共API的一部分。如果你在代码中使用它,你应该确保为它添加一个测试用例,因为它随时都可能崩溃!**从我所看到的来看,WebSocketProvider.disconnect
是在web3@1.0.0-beta.38
中引入的,并且在今天的最新发行版web3@1.0.0-beta.55
中仍然存在。我不认为从现在到web3@1.0.0
之间会有太大的变化,但是当涉及到内部API的结构时,没有什么限制。我已经和目前的维护者Samuel Furter,也就是GitHub上的nividia详细讨论过将内部提供者公开的问题。我不完全同意他将其保留在内部的决定,但他是目前唯一的维护者,他的手 * 非常 * 忙着稳定
1.0
分支上的长期工作。作为这些讨论的结果,我现在的意见是,那些需要一个稳定的API为他们的WebSocket提供者的人应该写一个他们自己的EIP-1193兼容的提供者,并将其发布在NPM上以供其他人使用。请永远遵循这一点,并在您自己的公共API中包含一个类似的
disconnect
方法。如果您用TypeScript
编写它,将获得加分。因为这使您能够显式地将类成员声明为public
、protected
或private
。如果您这样做,请注意EIP-1193仍处于草案状态,因此您需要密切关注EthereumMagicians和Provider Ring Discord上的EIP-1193讨论,以了解可能发生的任何更改。
2lpgd9683#
在node js进程结束时,只需调用: