node.js - 为什么我在 NodeJS express 应用中的上传不完整
问题描述
我需要在生成后将 v8 堆转储上传到 AWS S3 存储桶中,但是上传的文件为 0KB 或 256KB。服务器上的文件大小超过 70MB,因此请求似乎没有等到堆转储没有完全刷新到磁盘。我猜想通过管道传输的可读流是以 fs.createWriteStream
异步方式发生的,并且await
对函数的调用实际上并没有等待。我正在使用 v3 版本的 AWS NodeJS 开发工具包。我做错了什么?
代码
async function createHeapSnapshot (fileName) {
const snapshotStream = v8.getHeapSnapshot();
// It's important that the filename end with `.heapsnapshot`,
// otherwise Chrome DevTools won't open it.
const fileStream = fs.createWriteStream(fileName);
snapshotStream.pipe(fileStream);
}
async function pushHeapSnapshotToS3(fileName)
{
const heapDump = fs.createReadStream(fileName);
const s3Client = new S3Client();
const putCommand = new PutObjectCommand(
{
Bucket: "my-bucket",
Key: `heapdumps/${fileName}`,
Body: heapDump
}
)
return s3Client.send(putCommand);
}
app.get('/heapdump', asyncMiddleware(async (req, res) => {
const currentDateTime = Date.now();
const fileName = `${currentDateTime}.heapsnapshot`;
await createHeapSnapshot(fileName);
await pushHeapSnapshotToS3(fileName);
res.send({
heapdumpFileName: `${currentDateTime}.heapsnapshot`
});
}));
解决方案
你的猜测是正确的。返回一个承诺,但该createHeapSnapshot()
承诺与流完成时完全没有联系。因此,当调用者使用await
该承诺时,承诺在流实际完成之前很久就解决了。 async
函数没有任何魔力,无法以某种方式知道何时完成了非承诺的异步操作.pipe()
。因此,您的async
函数返回一个与流函数完全没有联系的承诺。
由于流对 Promise 没有太多的原生支持,因此您可以手动承诺流的完成和错误:
function createHeapSnapshot (fileName) {
return new Promise((resolve, reject) => {
const snapshotStream = v8.getHeapSnapshot();
// It's important that the filename end with `.heapsnapshot`,
// otherwise Chrome DevTools won't open it.
const fileStream = fs.createWriteStream(fileName);
fileStream.on('error', reject).on('finish', resolve);
snapshotStream.on('error', reject);
snapshotStream.pipe(fileStream);
});
}
或者,您可以使用支持 Promise 的较新pipeline()
功能(nodejs v15 中添加的内置 Promise 支持)并替换.pipe()
并具有内置错误监控以拒绝 Promise:
const { pipeline } = require('stream/promises');
function createHeapSnapshot (fileName) {
const snapshotStream = v8.getHeapSnapshot();
// It's important that the filename end with `.heapsnapshot`,
// otherwise Chrome DevTools won't open it.
return pipeline(snapshotStream, fs.createWriteStream(fileName))
}
推荐阅读
- c++ - 在 C++ 中获取设备的当前“活动”驱动程序
- swift - 一个用 Swift 编写的服务器中的致命错误将如何处理?
- objective-c - 'new' 已弃用:-init 不可用
- php - Wordpress:Slug 添加后缀
- r - cforest“树”中的权重加起来超过样本大小
- php - 计算在 Laravel 中有关系的关系
- vue.js - 将一个字段的值链接到另一个字段
- javascript - 创建一个 div 并给它一个 CSS 条目?
- c# - 无法转换类型的 COM 对象(不支持此类接口(来自 HRESULT 的异常:0x80004002 (E_NOINTERFACE)))
- javascript - 如何在 iOS 11.3 Safari 中禁用视口缩放?