Node.js中管道上传多字符串到Amazon S3 Bucket无数据问题排查
问题原因分析
- 重复调用S3.upload逻辑错误:S3 SDK的
upload方法接收流作为Body参数时,需要在流数据推送前仅初始化一次上传任务,让upload全程监听流的数据推送直到流结束。你当前在每次调用to方法时都重新创建一次upload任务,第一次调用to触发的upload只会捕获当前已推送到流的数据,后续to调用推送的数据不会被之前的upload任务接收,且多次upload会互相覆盖同key的对象,最终上传的内容为空或不完整。 - 流被多次消费导致数据分流:你在每次
to方法中都调用this.#stream?.pipe(process.stdout),pipe操作会消费流中的数据,同时S3的upload也在消费同一个流,会导致数据被stdout分流,S3无法拿到完整的流数据。 - upload等待时机错误:你在每次
to方法内就await S3.upload(...).promise(),但流是在finish方法调用推送null后才会标记结束,upload会一直等待流结束才会完成上传,这里会直接阻塞后续的to调用,甚至出现超时情况,永远等不到流结束。 - 缺少换行分隔符:你当前直接推送字符串
s到流中,最终三个字符串会拼接成连续的文本,不会得到每行一条的效果。
修复后的代码示例
export class S3Output extends Output { #stream: Readable | null = null #uploadPromise: Promise<void> | null = null async to(s: string): Promise<void> { // 推送时加换行符分隔 this.#stream?.push(s + '\n') } init(): void { this.#stream = new Readable() this.#stream._read = function () {}; // 初始化阶段就创建一次upload任务,全程监听流 const params = { Bucket: config.aws.bucketName, Body: this.#stream, Key: 'test.json' } // 流需要输出到stdout的话,在这里只pipe一次 this.#stream.pipe(process.stdout) // 存储upload的promise,留到finish时等待 this.#uploadPromise = S3.upload(params).promise() } async finish(): Promise<void> { // 推送null标记流结束 this.#stream?.push(null) // 等待上传完成 await this.#uploadPromise return } }
内容的提问来源于stack exchange,提问作者Le Rilleur
相关产品推荐
相关产品推荐

