web3 websocket连接阻止节点进程退出

时间:2018-05-31 20:15:14

标签: javascript websocket ethereum solidity web3

我有一个节点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()

任何人都有更优雅或官方认可的解决方案?我觉得有必要手动执行此操作,而不是让对象在进程结束时自行销毁。其他客户端似乎自动执行此操作而未明确告知他们关闭其连接。也许告诉你的节点进程创建的所有客户端在关机时关闭他们的句柄/连接是否更清楚,但对我来说,这是出乎意料的。

3 个答案:

答案 0 :(得分:1)

在节点js流程结束时,只需调用:

web3.currentProvider.connection.close()

答案 1 :(得分:1)

  

让我感到很有趣的是,您必须手动执行此操作,而不是让对象在进程结束时自行销毁

这很有趣,因为与异步相比,您可能已经接触了更多的同步编程。考虑下面的代码

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("Read data", data);处结束,但是您得到的是随后打印的另一条语句。现在感觉好笑吗?让我们在流程中添加退出语句

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引擎花时间执行挂起的回调。理想情况下,当没有工作要做时(没有挂起的回调,函数调用等),该过程会自动完成。这就是异步世界的工作方式。有一些不错的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()时,它将自动退出)

答案 2 :(得分:0)

由于EIP-1193impending release of Web3 1.0.0的实现,JavaScript web3模块的提供者API最近进行了一些重大更改。

the code,看来web3.currentProvider.disconnect()应该可以工作。如the MDN reference docs for WebSocket.close(...)中所述,此方法还接受可选的codereason参数。

重要提示:您会注意到我引用了上面的源代码,而不是文档。这是因为目前disconnect方法不被认为是公共API的一部分。如果在代码中使用它,则应确保为其添加一个测试用例,因为它可能随时中断!据我所知,WebSocketProvider.disconnect是在{{1}中引入的},并在今天的最新版本web3@1.0.0-beta.38中仍然存在。鉴于稳定的1.0.0版本即将发布,我认为从现在到web3@1.0.0-beta.55之间这种变化不太可能发生,但是内部API的结构没有任何限制

我已经与GitHub的当前维护者Samuel Furter(又名nividia)公开讨论了内部提供商的详细信息。我不同意他决定在内部保留它的决定,但是在他的辩护中,他是目前唯一的维护者,他非常全力以赴地稳定正在进行中的长期工作。 web3@1.0.0分支。

作为这些讨论的结果,我目前的观点是,那些需要为WebSocket提供程序提供稳定API的人应该编写自己的EIP-1193兼容提供程序,并将其发布在NPM上以供其他人使用。为此,请遵循semver,并在您自己的公共API中包含类似的1.0方法。如果您使用disconnect编写奖励积分,则可以将类成员显式声明为TypeScriptpublicprotected

如果执行此操作,请注意EIP-1193仍处于草稿状态,因此您需要密切注意EthereumMagiciansProvider Ring Discord上的EIP-1193讨论,随时应对可能发生的任何变化。