假设我想将一些旧的异步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它是微不足道的 - SourceQueueWithComplete
有complete
和fail
方法。
更新: 通过在Option中包装元素并将None视为停止读取流的信号,以及使用Promise传播错误,我能够获得足够好的结果:
queue.dequeue
.interruptWhen(interruptingPromise.get)
.takeWhile(_.isDefined).map(_.get)
但是,我是否忽略了更自然的做事方式?
答案 0 :(得分:4)
更新的答案:将unNoneTerminate
与rethrow
结合使用,这将花费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
就会终止。