使用ssh2-sftp-client
库从SFTP站点下载多个文件时出现错误。抛出的错误似乎表明在每次下载完成后未清除节点流。这导致我的应用程序发生内存泄漏。在生产环境中,我需要能够下载数千个文件,因此这种内存泄漏非常严重。如何关闭流,以便在下载每个文件后释放内存?
代码:
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();
});
注意:此代码使用公共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
答案 0 :(得分:1)
因此,您说您正在尝试下载产品中的数千个文件,但每个文件都使用了侦听器。 Node仅允许您在触发警报之前最多创建10
个事件侦听器。
请参阅:
https://nodejs.org/dist/latest-v8.x/docs/api/events.html#events_eventemitter_defaultmaxlisteners https://github.com/nodejs/help/issues/1051
如果您要更正此问题,建议您实施queue
,一次仅下载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();
});