web3 websocket connection prevents node process from exiting
我有一个节点JS进程,它创建了Web3 WebSocket连接,如下所示:
1 | web3 = new Web3('ws://localhost:7545') |
当进程完成时(我给它发送一个sigterm),它不会退出,而是永远挂起,没有控制台输出。
我在sigint和sigterm上注册了一个监听器,观察在哪些处理过程中,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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> } |
为了完整起见,下面是监听信号的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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对象有一个关闭或结束方法。
手动关闭上述
1 | web3.currentProvider.connection.close() |
有人有更优雅或官方认可的解决方案吗?我觉得很有趣的是,您必须手动执行此操作,而不是让对象在进程结束时自行销毁。其他客户机似乎会自动执行此操作,而不会明确告诉他们关闭连接。也许告诉您的节点进程创建的所有客户机在关闭时关闭它们的句柄/连接会更干净,但对我来说,这是意外的。
It feels funny to me that you have to manually do this rather than have the object destroy itself on process end
这感觉很有趣,因为与异步编程相比,您可能接触过更多的同步编程。考虑下面的代码
1 2 3 | fs = require('fs') data = fs.readFileSync('file.txt', 'utf-8'); console.log("Read data", data) |
当你在上面运行时,你得到输出
1 2 | $ node sync.js Read data Hello World |
这是一个同步代码。现在考虑相同的异步版本
1 2 3 4 5 | 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); |
当你运行时,你得到下面的输出
1 2 3 | $ node async.js Read data undefined Got data back from file Hello World |
现在,如果您认为是一个同步程序员,程序应该在最后一个
1 2 3 4 5 6 | 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) |
现在,当您运行程序时,它将在最后一条语句结束。
1 2 | $ node async.js Read data undefined |
但文件实际上并没有被读取。为什么?因为您从未给javascript引擎时间来执行挂起的回调。理想情况下,当没有剩余的工作可供处理时(没有挂起的回调、函数调用等),进程会自动完成。这就是异步世界的工作方式。有一些很好的,所以线程和文章你应该研究
https://medium.freecodecamp.org/walking-inside-nodejs-event-loop-85caeca391a9
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
如何退出node.js
为什么我的node.js进程在删除所有侦听器后不终止?
node.js进程如何知道何时停止?
因此,在异步世界中,您需要告诉进程退出,否则当没有挂起的任务(您知道如何检查-
在节点JS过程的末尾,只需调用:
1 | web3.currentProvider.connection.close() |
由于EIP-1193的实现以及即将发布的Web3 1.0.0,Javascript Web3模块的提供者API最近发生了一些实质性的变化。
根据代码,似乎
重要提示:您会注意到我引用了上面的源代码,而不是文档。这是因为目前,
我已经和现在的维护者,Samuel Futter,也就是Github上的Nividia讨论了如何让内部供应商公开。我不完全同意他决定将其保留在这里的决定,但在他的辩护中,他是目前唯一的维护者,而且他非常全力地稳定了在
由于这些讨论的结果,我现在的观点是,那些需要为自己的WebSocket提供商提供一个稳定的API的人应该自己编写一个兼容EIP-1193的提供商,并将其发布到NPM上供其他人使用。请遵循semver,并在您自己的公共API中包含类似的
如果您这样做,请注意,EIP-1193仍处于草稿状态,因此您需要密切关注关于以太坊制造商的EIP-1193讨论以及提供商之间的关系,以了解可能发生的任何变化。