- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
使用 ssh2-sftp-client
库从 SFTP 站点下载多个文件时出现错误。抛出的错误似乎表明 Node 流在每次下载完成后都没有被清除。这导致我的应用程序发生内存泄漏。在生产环境中,我需要能够下载数千个文件,因此这种内存泄漏非常严重。如何关闭流以便在下载每个文件后释放内存?
代码:
const Client = require('ssh2-sftp-client');
const sftp = new Client();
sftp.connect({
host: '195.144.107.198',
port: 22,
username: 'demo',
password: 'password'
}).then(async () => {
const fileNames = ['readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt'];
// Loop through filenames
for (let i = 0; i < fileNames.length; i++) {
// Download all the files synchronously (1 at a time)
const fileName = fileNames[i];
await new Promise((resolve, reject) => { // <-- note the await
sftp.get(fileName, true, 'utf8').then((stream) => {
let text = '';
stream
.on('data', (d) => { text += d; })
.on('end', () => {
console.log('Success downloaded file', i);
resolve(text);
});
}).catch((err) => {
console.log('Error downloading file', err);
reject(err.message)
});
});
}
sftp.end();
});
注意:此代码使用公共(public) SFTP 站点,因此凭据不敏感,您可以运行它进行测试。在这里找到:https://www.sftp.net/public-online-sftp-servers
错误(下载文件 #9 后发生):
(node:44580) MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
11 error listeners added. Use emitter.setMaxListeners() to increase limit
最佳答案
所以你说你正试图在 prod 中下载数千个文件,但你正在为每个文件使用一个监听器。 Node 只允许您在触发警报之前创建最多 10
个事件监听器。
参见:
https://nodejs.org/dist/latest-v8.x/docs/api/events.html#events_eventemitter_defaultmaxlisteners https://github.com/nodejs/help/issues/1051
如果您想纠正这个问题,我建议您实现一个队列
,并且一次只下载 10 个文件。
类似于:
const Client = require('ssh2-sftp-client');
const sftp = new Client();
sftp.connect({
host: '195.144.107.198',
port: 22,
username: 'demo',
password: 'password'
}).then(async () => {
// Treat files array as a queue instead of an array
const fileQueue = ['readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt', 'readme.txt'];
// Use this function to grab files from your main files array
const downloadFilesFromQueue = (fileName) =>
new Promise((resolve, reject) => {
// Sanity check
if(!fileName) {
resolve();
}
sftp.get(fileName, true, 'utf8').then((stream) => {
let text = '';
stream
.on('data', (d) => { text += d; })
.on('end', () => {
console.log('Success downloaded file', fileName);
resolve(text);
});
}).catch((err) => {
console.log('Error downloading file', err);
reject(err.message);
});
})
// Handle errors
.catch((err) => console.log(err.message))
// Get next file from the queue
.then(() => {
// If there are no more items in the queue, we're done
if (!fileQueue.length) {
return;
}
downloadFilesFromQueue(fileQueue.shift())
});
// Track all unresolved promises
const unresolvedPromises = [];
// Request no more than 10 files at a time.
for (let i = 0; i < 10; i++) {
// Use file at the front of the queue
const fileName = fileQueue.shift();
unresolvedPromises.push(downloadFilesFromQueue(fileName));
}
// Wait until the queue is emptied and all file retrieval promises are
// resolved.
await Promise.all(unresolvedPromises);
// done
sftp.end();
});
关于javascript - 下载多个SFTP文件时NodeJS报错 "Possible EventEmitter memory leak detected. 11 error listeners added",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52825092/
我已经尝试了很长时间自己解决这个问题,但找不到适合我的问题的解决方案。 我有这个方法: handle_database = function(callback, req, res) { pool.ge
我差点把问题标题写成 - Communicating between eventEmitters 我有一个全局范围内的 node.js 模块 (X)(它使用 eventEmitter)。然后我有每个套
我正在尝试从一个 EventEmitter 发射到另一个 EventEmitter,或者寻找替代解决方案。下面的代码不起作用。 多发射器示例 var events = require('events'
有很多示例在自定义事件发射器构造函数中未使用 events.EventEmitter.call(this),而其他示例正在使用它 (official documentation): var event
假设我有这段代码: export class ProductsListComponent { @Output() onProductSelected: EventEmitter; constr
有时我们会遇到泛型变量应该被省略的情况。像这样: @Component( ... ) class MyComponent { @Output() public cancel = new Eve
我想做这样的事情: var events = require("events"); var emitterA = new events.EventEmitter(); var emitterB = n
EventEmitter.emit() 和 EventEmitter.next() 有什么区别?两者都将事件分派(dispatch)给订阅的监听器。 export class MyService {
我是 angular2 的新手,我对使用 EmitterService 的 EventEmitter 感到困惑,任何人都可以向我解释 Emitter 的用途。 在不使用@input 和@output
我正在学习 Node.js,对自定义 EventEmitter 有一些困惑。代码如下: var events = require("events"); function MyEmitter (name
如标题所述,我想用 TypeScript 重写下面的语句 EventEmitter = require('events').EventEmitter ES6风格 import {EventEmitte
obj.prototype.__proto__ = events.EventEmitter.prototype 我有时会看到上面的代码,我用谷歌搜索了一下,他们说这一行将所有 EventEmitter
我创建了一个抽象父类(super class)来处理我应用中各种表单组件的通用因素。 出于某种原因,我无法正确捕获由在父类(super class)中声明了 EventEmitter 的派生类发出的事
我尝试将表单从我的子组件传递给他的父组件。 child TS: @Output() submit: EventEmitter = new EventEmitter(); updateStream():
这真的很奇怪,也很难解释。 我用过EventEmitter在我的一些服务中,我一直在使用它来更改我的 View 数据。 我遇到了更改路线(通过链接或通过历史返回)的问题,它似乎被多次触发,因此它搞乱了
我正在开发一个 Angular2 组件,它使用网络摄像头将图片捕捉到 Canvas 元素,并将其提取为 Blob。 Blob 和事件分别正常工作,但是当我尝试从 toBlob 的回调函数内发出事件时,
当我有一个带有选择器'recursive-element'的模板时,它的模板看起来像这样 在我定义的类中 greetEvent = new EventEmitter
我非常喜欢将函数导出为 JavaScript 模块的主要 API 的模式。原因是在 JS 中,函数基本上可以做典型对象可以做的任何事情,然后再做一些。 所以这对我来说很典型: function stu
我有这个 Node js脚本: var EventEmitter = require('events').EventEmitter, util = require('util'); var p
在事件生成后附加事件处理程序有一个看似众所周知的问题。这主要是在调用遵循返回 EventEmitter 模式的函数时出现的问题,例如: var EventEmitter = require('even
我是一名优秀的程序员,十分优秀!