我有一个节点js流程,它创建了一个web3 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()
})
似乎web3保持套接字打开,这是有道理的,因为我从未告诉过它关闭连接。浏览文档并进行谷歌搜索,看起来好像没有web3对象的close方法或end方法。
手动关闭上面
stop
中的套接字可以使进程成功退出:web3.currentProvider.connection.close()
有人有一个更优雅或更正式认可的解决方案吗?对我来说,您必须手动执行此操作,而不是让对象在过程结束时销毁自己,这使我感到很有趣。其他客户端似乎自动执行此操作,而没有明确告诉他们关闭其连接。告诉您由节点进程创建的所有客户端无论如何都要在关闭时关闭它们的句柄/连接,这也许是更干净的方法,但是对我来说,这是出乎意料的。
最佳答案
由于EIP-1193和impending release of Web3 1.0.0的实现,JavaScript web3模块的提供者API最近进行了一些重大更改。
对于the code,似乎web3.currentProvider.disconnect()
应该可以工作。此方法还接受可选的code
和reason
参数,如the MDN reference docs for WebSocket.close(...)
中所述。
重要提示:您会注意到我引用了上面的源代码,而不是文档。这是因为目前不将disconnect
方法视为公共(public)API的一部分。如果在代码中使用它,则应确保为其添加一个测试用例,因为它可能随时中断! 据我所知,WebSocketProvider.disconnect
是在web3@1.0.0-beta.38
中引入的,并且至今仍存在于最新版本web3@1.0.0-beta.55
中。鉴于稳定的1.0.0版本即将发布,我认为现在和web3@1.0.0
之间的变化不太可能发生,但是内部API的结构没有任何限制。
我已经与GitHub的现任维护者Samuel Furter(又名nividia)公开讨论了内部提供者的详细信息。我不同意他决定将其保留在内部的决定,但是出于辩护,他是目前唯一的维护者,他在稳定1.0
分支上长期进行的工作方面非常专心。
作为这些讨论的结果,我目前的观点是,那些需要为其WebSocket提供程序提供稳定API的人应该编写自己的EIP-1193兼容提供程序,并将其发布在NPM上以供其他人使用。为此,请遵循semver,并在您自己的公共(public)API中包含类似的disconnect
方法。如果您使用TypeScript
编写奖励积分,则可以将类成员显式声明为public
,protected
或private
。
如果这样做,请注意EIP-1193仍处于草稿状态,因此您需要密切注意EthereumMagicians和Provider Ring Discord上的EIP-1193讨论,以随时掌握可能发生的任何更改。