node.js - 在谷歌云功能中运行节点js导出
问题描述
我们需要导出一个 zip 文件,其中包含大量数据(几 GB)。zip 存档需要包含大约 50-100 个 indesign 文件(每个大约 100mb)和一些其他较小的文件。我们尝试使用谷歌云功能来实现它(成本更低等)。该功能通过配置文件触发,该文件上传到存储桶中。配置文件包含需要将哪些文件放入 zip 中的所有信息。不幸的是,总是达到 2gb 的内存限制,所以函数永远不会成功。
我们尝试了不同的方法:第一个解决方案是循环文件,创建 Promise 以下载它们,在循环完成后,我们尝试一次解决所有 Promise。(文件通过流直接下载到文件中)。第二次尝试是等待 for 循环内的每次下载,但再次达到内存限制。
所以我的问题是:为什么 node js 不清除流?似乎节点将每个流文件保存在内存中并最终崩溃。我已经尝试按照此处的建议将 readStream 和 writeStream 设置为 null:
但没有变化。
注意:我们从来没有达到这一点,所有文件都被下载以创建 zip 文件。在第一个文件之后它总是失败。
请参阅下面的代码片段:
// first try via promises all:
const promises = []
for (const file of files) {
promises.push(downloadIndesignToExternal(file, 'xxx', dir));
}
await Promise.all(promises)
// second try via await every step (not performant in terms of execution time, but we wanted to know if memory limit is also reached:
for (const file of files) {
await downloadIndesignToExternal(file, 'xxx', dir);
}
// code to download indesign file
function downloadIndesignToExternal(activeId, externalId, dir) {
return new Promise((resolve, reject) => {
let readStream = storage.bucket(INDESIGN_BUCKET).file(`${activeId}.indd`).createReadStream()
let writeStream = fs.createWriteStream(`${dir}/${externalId}.indd`);
readStream.pipe(writeStream);
writeStream.on('finish', () => {
resolve();
});
writeStream.on('error', (err) => {
reject('Could not write file');
})
})
}
解决方案
重要的是要知道 /tmp (os.tmpdir()) 是Cloud Functions 中基于内存的文件系统。当您将文件下载到 /tmp 时,它会占用内存,就像您将文件保存到内存中的缓冲区一样。
如果您的函数需要的内存超出了可以为函数配置的内存,那么 Cloud Functions 可能不是解决此问题的最佳方案。
如果您仍想使用 Cloud Functions,则必须找到一种将输入文件直接流式传输到输出文件的方法,但无需在函数中保存任何中间状态。我确信这是可能的,但您可能需要为此编写大量额外的代码。
推荐阅读
- postgresql - 在我的 MAC 上登录 POSTGRES 时出现密码错误
- javascript - 在 html 中使用来自 Webpack 4 的输入调用全局函数
- c# - c#中的透视图
- flutter - Flutter Listview 滑动更改 TabBar 索引
- flutter - 颤振 pubspec.yaml 错误
- unit-testing - org.springframework.web.util.NestedServletException : 单元测试中的 MockMVC 请求处理失败
- javascript - React 如何管理生产中的状态
- python - 使用 Gekko 求解具有固定端点的最优控制
- python - pandas DataFrame中文本列的左对齐格式 - 不适用于空格
- python - 将 Matlab 代码转换为 Python 的有效方法