nodejs / nodejs/node

Partially consuming fs.ReadStream closes file handle despite `autoClose: false`

オープン
#45,721 コメント 7 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

fs stream
主要言語
JavaScript
スター
122k
フォーク
37.3k
平均マージ
4日 2時間
マージ済み PR(30日)
283

説明

Version

v19.2.0, v14.21.1

Platform

Linux wolf-x1c6 5.15.0-53-generic #59-Ubuntu SMP Mon Oct 17 18:53:30 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?
import fsPromises from 'node:fs/promises'

const fh = await fsPromises.open('example.txt')
fh.on('close', () => {throw new Error('handle closed!')})

const stream = fh.createReadStream({
	autoClose: false,
})

for await (const chunk of stream) {
	break
}

// Give the event loop a breather: this seems to be where the close happens
await new Promise(resolve => setTimeout(resolve, 10))

console.log('fd', fh.fd) // = -1; stream closed
How often does it reproduce? Is there a required condition?

Always

What is the expected behavior?

FileHandle.createReadStream({autoClose: false}) should result in the file handle not being automatically closed when the stream is destroyed.

What do you see instead?

Using fs.ReadStream[Symbol.asyncIterator] seems to unconditionally close the file handle (after a small delay; I guess at the end of the event loop or something? but haven't dug in; just noted the setTimeout above is necessary to reproduce) despite {autoClose: false} being passed to FileHandle.createReadStream().

This seems to be the result of the underlying readable.destroy() also closing the file handle; but it means that, as far as I can tell, there's no way to only partially consume an fs.ReadStream created from a file handle without either closing the handle or leaking the stream.

Additional information

No response

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

提供された再現手順から始め、部分的な非同期反復中の FileHandle.createReadStream()、fs.ReadStream[Symbol.asyncIterator]、および readable.destroy() を追跡します。autoClose: false であるにもかかわらずファイルハンドルが閉じるタイミングを確認し、その後、ストリームをリークさせずに反復を中断した後もハンドルが開いたままになることを確認します。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
javascript, nodejs
領域
operating-systems
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
静か
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。