FS2:是否可以优雅地完成队列?

时间:2018-05-07 11:13:26

标签: scala fs2

假设我想将一些旧的异步API转换为FS2 Streams。 API提供了一个包含3个回调的接口:下一个元素,成功,错误。 我希望Stream发出所有元素,然后在收到成功或错误回调后完成。

FS2指南(https://functional-streams-for-scala.github.io/fs2/guide.html)建议在这种情况下使用fs2.Queue, 它很适合入队,但到目前为止我看到的所有例子都预计queue.dequeue返回的流将永远不会完成 - 在我的情况下,没有明显的方法来处理成功/错误回调。 我尝试使用queue.dequeue.interruptWhen(...here goes the signal...),但如果在客户端从流中读取数据之前到达成功/错误回调, 流过早地终止 - 仍然有未读元素。我希望消费者在完成流之前完成阅读。

用FS2可以做到吗?使用Akka Streams它是微不足道的 - SourceQueueWithCompletecompletefail方法。

更新: 通过在Option中包装元素并将None视为停止读取流的信号,以及使用Promise传播错误,我能够获得足够好的结果:

queue.dequeue
.interruptWhen(interruptingPromise.get)
.takeWhile(_.isDefined).map(_.get)

但是,我是否忽略了更自然的做事方式?

2 个答案:

答案 0 :(得分:4)

更新的答案:将unNoneTerminaterethrow结合使用,这将花费Stream[F, Either[Throwable, A]]并返回Stream[F, A],当它{可抛出。

您的完整堆栈将是Stream.raiseError,您可以通过调用Stream[F, Either[Throwable, Option[A]]]

来展开Stream[F,A]

答案 1 :(得分:3)

一种惯用的方法是创建一个Queue[Option[A]]而不是Queue[A]。入队时,请包裹在Some中,然后您可以显式入队None来表示完成。在出队方面,执行q.dequeue.unNoneTerminate,这会给您一个Stream[F, A],一旦队列发出None

,该while就会终止。