如何将scalaz-stream连接到反应流(如reactive-streams.org中)

时间:2015-02-26 06:57:57

标签: slick scalaz-stream

我想通过scalaz-stream通过db.stream(你的查询)流式传输从一个灵活的3.0.0查询返回的数据。

看起来,reactive-streams.org使用的是不同库实现的API和数据流模型。

如何通过从scalaz-stream流程回流到光滑的出版商的背压来做到这一点?

3 个答案:

答案 0 :(得分:3)

查看https://github.com/krasserm/streamz

Streamz是scalaz-stream的资源组合器库。它允许Process实例使用和生成:

  • Apache Camel端点
  • Akka Persistence日记帐和快照商店
  • Akka Stream以完全背压支撑流动(反应流)

答案 1 :(得分:2)

我终于回答了我自己的问题。如果您愿意使用scalaz-streams队列来排队流式传输结果。

def getData[T](publisher: slick.backend.DatabasePublisher[T],
  queue: scalaz.stream.async.mutable.Queue[T], batchRequest: Int = 1): Task[scala.concurrent.Future[Long]] =
  Task {
    val p = scala.concurrent.Promise[Unit]()
    var counter: Long = 0
    val s = new org.reactivestreams.Subscriber[T] {
      var sub: Subscription = _

      def onSubscribe(s: Subscription): Unit = {
        sub = s
        sub.request(batchRequest)
      }

      def onComplete(): Unit = {
        sub.cancel()
        p.success(counter)
      }

      def onError(t: Throwable): Unit = p.failure(t)

      def onNext(e: T): Unit = {
        counter += 1
        queue.enqueueOne(e).run
        sub.request(batchRequest)
      }
    }
    publisher.subscribe(s)
    p.future
  }

当您使用run运行此操作时,您将获得一个完成后的未来,意味着查询已完成流式传输。如果您希望计算等待所有数据到达,您可以撰写此未来。您还可以在getData中的任务中添加使用Await,然后如果您需要在继续之前运行所有数据,则在返回的Task对象上组合您的计算。对于我所做的事情,我将在未来完成并关闭队列,以便我的scalaz-stream知道干净地终止。

答案 2 :(得分:0)

这是一个稍微不同的实现(比用户1763729发布的实现)返回一个进程:

def getData[T](publisher: DatabasePublisher[T], batchSize: Long = 1L): Process[Task, T] = {
 val q = async.boundedQueue[T](10)

 val subscribe = Task.delay {
  publisher.subscribe(new Subscriber[T] {

    @volatile var subscription: Subscription = _

    override def onSubscribe(s: Subscription) {
      subscription = s
      subscription.request(batchSize)
    }

    override def onNext(next: T) = {
        q.enqueueOne(next).attemptRun
        subscription.request(batchSize)
    }

    override def onError(t: Throwable) = q.fail(t).attemptRun

    override def onComplete() = q.close.attemptRun
  })
 }

 Process.eval(subscribe).flatMap(_ => q.dequeue)
}