From 9d8b73386e34322ce40bc399de0a33a0864db66b Mon Sep 17 00:00:00 2001 From: Fabien Carrion Date: Sat, 18 Jan 2025 12:52:21 -0600 Subject: [PATCH 1/2] fix : ZStream Broadcastdynamic hanging --- .../test/scala/zio/stream/ZStreamSpec.scala | 38 +++++++++++++++++++ .../src/main/scala/zio/stream/ZStream.scala | 4 +- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/streams-tests/shared/src/test/scala/zio/stream/ZStreamSpec.scala b/streams-tests/shared/src/test/scala/zio/stream/ZStreamSpec.scala index 9734f1ae8eb2..4ef50912184b 100644 --- a/streams-tests/shared/src/test/scala/zio/stream/ZStreamSpec.scala +++ b/streams-tests/shared/src/test/scala/zio/stream/ZStreamSpec.scala @@ -539,6 +539,44 @@ object ZStreamSpec extends ZIOBaseSpec { } } ), + suite("broadcastDynamic")( + test("Values") { + val stream = ZStream.range(0, 5) + for { + broadcasted <- stream.broadcastDynamic(12) + out1 <- stream.runCollect + out2 <- broadcasted.runCollect + expected = Chunk.fromIterable(Range(0, 5)) + } yield assert(out1)(equalTo(expected)) && assert(out2)(equalTo(expected)) + }, + test("Errors") { + val stream = ZStream.range(0, 1) ++ ZStream.fail("Boom") + for { + broadcasted <- stream.broadcastDynamic(12) + out1 <- stream.runCollect.either + out2 <- broadcasted.runCollect.either + expected = Left("Boom") + } yield assert(out1)(equalTo(expected)) && assert(out2)(equalTo(expected)) + }, + test("Unsubscribe") { + val stream = ZStream.range(0, 5) + for { + broadcasted <- stream.broadcastDynamic(12) + _ <- stream.toPull.ignore + out2 <- broadcasted.runCollect + } yield assert(out2)(equalTo(Chunk.fromIterable(Range(0, 5)))) + }, + test("Cleanup Resources") { + for { + finalized <- Ref.make(false) + stream = ZStream.range(0, 5).ensuring(finalized.set(true)) + broadcasted <- stream.broadcastDynamic(2) + _ <- stream.runCollect + _ <- broadcasted.runCollect + cleaned <- finalized.get + } yield assertTrue(cleaned) + } + ) @@ TestAspect.timeout(5.seconds), suite("buffer")( test("maintains elements and ordering")(check(tinyChunkOf(tinyChunkOf(Gen.int))) { chunk => assertZIO( diff --git a/streams/shared/src/main/scala/zio/stream/ZStream.scala b/streams/shared/src/main/scala/zio/stream/ZStream.scala index 763233e36202..e41ccbc6572d 100644 --- a/streams/shared/src/main/scala/zio/stream/ZStream.scala +++ b/streams/shared/src/main/scala/zio/stream/ZStream.scala @@ -344,7 +344,7 @@ final class ZStream[-R, +E, +A] private (val channel: ZChannel[R, Any, Any, Any, )(implicit trace: Trace): ZIO[R with Scope, Nothing, ZStream[Any, E, A]] = self .broadcastedQueuesDynamic(maximumLag) - .map(ZStream.scoped(_).flatMap(ZStream.fromQueue(_)).flattenTake) + .flatMap(_.map(ZStream.fromQueueWithShutdown(_).flattenTake)) /** * Converts the stream to a scoped list of queues. Every value will be @@ -3437,7 +3437,7 @@ final class ZStream[-R, +E, +A] private (val channel: ZChannel[R, Any, Any, Any, capacity: => Int )(implicit trace: Trace): ZIO[R with Scope, Nothing, Hub[Take[E1, A1]]] = for { - hub <- ZIO.acquireRelease(Hub.bounded[Take[E1, A1]](capacity))(_.shutdown) + hub <- Hub.bounded[Take[E1, A1]](capacity) _ <- self.runIntoHubScoped(hub).forkScoped } yield hub From 408f9c9489de7c8e8619ab25c017cb702eb8de73 Mon Sep 17 00:00:00 2001 From: Fabien Carrion Date: Mon, 20 Jan 2025 22:37:38 -0600 Subject: [PATCH 2/2] fix : ZStream Broadcastdynamic hanging --- streams/shared/src/main/scala/zio/stream/ZStream.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/streams/shared/src/main/scala/zio/stream/ZStream.scala b/streams/shared/src/main/scala/zio/stream/ZStream.scala index e41ccbc6572d..96ef2cbdabc7 100644 --- a/streams/shared/src/main/scala/zio/stream/ZStream.scala +++ b/streams/shared/src/main/scala/zio/stream/ZStream.scala @@ -3437,7 +3437,7 @@ final class ZStream[-R, +E, +A] private (val channel: ZChannel[R, Any, Any, Any, capacity: => Int )(implicit trace: Trace): ZIO[R with Scope, Nothing, Hub[Take[E1, A1]]] = for { - hub <- Hub.bounded[Take[E1, A1]](capacity) + hub <- ZIO.acquireRelease(Hub.bounded[Take[E1, A1]](capacity))(_.shutdown) _ <- self.runIntoHubScoped(hub).forkScoped } yield hub