Reading from a socket gets stuck on Node.js 26
メンテナーはふだん 3 日以内に返信
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 72/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- node.js, scala
- 領域
- networking
調査の方向性
IoPlatformSuiteについて説明されている再現テストから始め、次にNodeの'readable'イベントでread()を呼び出すScala.jsのreadable-streamコードを追ってください。バッファリングされたチャンクの回帰テストを追加し、Node.js 26ですべてのデータを読み取ることを確認するとともに、古いNode.jsバージョンとの互換性も維持してください。
索引モデルが issue の本文から書いたものです。
説明
On Node.js 26, socket.reads can stop returning data even though the data has arrived. It works on Node.js 25 and earlier.
- fs2-io 3.14.0, also on
main(419d575) - cats-effect 3.7.1
- Scala 2.13 and 3.3.7
- Scala.js 1.22.0, Node.js 26.13.0, macOS
- JVM and Native are fine
How to reproduce
This test, added to IoPlatformSuite, puts three pieces of data in a stream and reads them. On Node.js 26 it times out after getting only the first piece:
test("reads every chunk already buffered in a Readable") {
def readable = {
val duplex = new facade.stream.Duplex(
new facade.stream.DuplexOptions {
var autoDestroy = false
var read = _ => ()
var write = (_, _, _, _) => ()
var `final` = (_, _) => ()
var destroy = (_, _, _) => ()
}
)
List[Byte](0, 1, 2).foreach(b => duplex.push(Chunk(b, b).toUint8Array))
duplex
}
Stream
.resource(suspendReadableAndRead[IO, Duplex]()(readable))
.flatMap(_._2)
.take(6)
.compile
.toList
.timeout(1.second)
.assertEquals(List[Byte](0, 0, 1, 1, 2, 2))
}
You can also see it with a real socket:
//> using scala 3.3.7
//> using platform scala-js
//> using jsVersion 1.22.0
//> using jsModuleKind common
//> using dep co.fs2::fs2-io::3.14.0
import cats.effect.{IO, IOApp, Resource}
import com.comcast.ip4s.*
import fs2.io.net.Network
import scala.concurrent.duration.*
import scala.scalajs.js
object Main extends IOApp.Simple {
private val net = js.Dynamic.global.require("net")
// sends 8 bytes three times, 50ms apart, then stays quiet
private val server: Resource[IO, Int] =
Resource.make(IO.async_[js.Dynamic] { cb =>
val s = net.createServer { (socket: js.Dynamic) =>
socket.write("aaaaaaaa")
js.timers.setTimeout(50)(socket.write("bbbbbbbb"))
js.timers.setTimeout(100)(socket.write("cccccccc"))
()
}
s.listen(0, "127.0.0.1", () => cb(Right(s)))
})(s => IO(s.close()).void).map(_.address().port.asInstanceOf[Int])
val run: IO[Unit] =
server.use { port =>
Network[IO].connect(SocketAddress(ipv4"127.0.0.1", Port.fromInt(port).get)).use { socket =>
// wait until all 24 bytes have arrived, then read them
IO.sleep(500.millis) >>
socket.reads.chunks
.evalTap(chunk => IO.println(s" got ${chunk.size} bytes"))
.flatMap(fs2.Stream.chunk)
.take(24)
.compile
.count
.timeout(3.seconds)
.attempt
.flatMap {
case Right(n) => IO.println(s"Node ${js.Dynamic.global.process.version}: read all $n bytes")
case Left(_) => IO.println(s"Node ${js.Dynamic.global.process.version}: got stuck, the rest never came")
}
}
}
}
On Node.js 26:
got 8 bytes
got 8 bytes
Node v26.13.0: got stuck, the rest never came
On Node.js 25 (same on 24 and 22):
got 8 bytes
got 16 bytes
Node v25.9.0: read all 24 bytes
Why
Node.js 26 changed readable.read(): it now returns one piece of the buffered data at a time, where it used to return all of it (nodejs/node#60441).
fs2 calls read() once each time Node fires 'readable'. Node only fires 'readable' again once everything has been read or more data comes in. So on Node.js 26, if nothing else comes in, the rest of the data is never read.
Fix
Keep calling read() until it returns null. On older Node.js versions the first call already returns everything, so nothing changes. PR to follow.
- 主要言語
- Scala
- スター
- 2.5k
- フォーク
- 633
- 平均マージ
- 4日 16時間
- マージ済み PR(30日)
- 5
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
typelevel/fs2 のほかの issue
-
Unix socket bind may delete an existing file when binding fails対応中かも @abhinav-phi が 1 日前に担当しました。 オープンbug
難易度 3/5 1〜2日 初心者へのやさしさ 55/100
メンテナーはふだん 3 日以内に返信
-
Scala Native TLSSocket#applicationProtocol behavior is inconsistent with JVM対応中かも @reardonj が 17 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 25/100
メンテナーはふだん 3 日以内に返信
-
Feature Proposal: report progress writing to sockets対応中かも @reardonj が 24 日前に担当しました。 オープン
難易度 5/5 1週間以上 初心者へのやさしさ 45/100
メンテナーはふだん 3 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
typelevel/fs2#3719 · コメント 2 件 ·
メンテナーはふだん 3 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 55/100
メンテナーはふだん 3 日以内に返信
似ている issue
-
[GC] Empty or non-numeric GC_*_HEAP_SIZE reads out of bounds or uses an uninitialised size対応中かも @oluies が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
scala-native/scala-native#5177 ·
メンテナーはふだん 1 日以内に返信
-
good first issue
難易度 1/5 1時間未満 初心者へのやさしさ 78/100
promovolve/promovolve#358 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 95/100
svroonland/zio-kinesis#1431 ·
-
area:build priority:P2 status:backlog
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
KD5UJC-XYZ/scarab#648 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
lichess-org/lila#22324 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信