如何在Scala中使用Monix消耗分页资源?

时间:2017-07-15 14:23:05

标签: scala monix

我有一个分页资源,我想用Monix递归地使用它。我想要一个Observable,它将发出下载的元素并递归地使用页面。这是一个简单的例子。它当然不起作用。它会发出第一页,然后是第一页+第二页,然后是第一页+第二页+第三页。我希望它先发射,然后发射,然后发射第三,依此类推。

object Main extends App {

  sealed trait Event
  case class Loaded(xs: Seq[String]) extends Event
  // probably should just finish stream instead of this event
  case object Done extends Event

  // here is the problem
  def consume(page: Int, size: Int):Observable[Event] = {
    Observable.fromFuture(getPaginatedResource(page, size)).concatMap{ xs =>
      if (xs.isEmpty) Observable.pure(Done)
      else Observable.concat(Observable.pure(Loaded(xs)), consume(page + 1, size + 5))
    }
  }

  def getPaginatedResource(page: Int, size: Int):Future[Seq[String]] = Future {
    if (page * size > 100) Seq.empty
    else 0 to size map (x => s"element $x")
  }

  consume(page = 0, size = 5).foreach(println)

}

有什么想法吗?

UPD 对不起,它似乎正在运行,我只是有一个错误size + 5。所以问题似乎已经解决了,但如果你发现我做错了什么,请告诉我。

1 个答案:

答案 0 :(得分:1)

通常建议尽可能在每次使用Observable时避免递归。因为它不容易可视化并且通常更容易出错。

一个想法是使用scanEvalF,因为它会在每个步骤中发出项目。

sealed trait Event
object Event {
  case class Loaded(page: Int, size: Int, items: Seq[String]) extends Event
}

def getPaginatedResource(page: Int, size: Int): Task[Loaded] = Task.pure {
  if (page * size > 100) Loaded(page, size, Seq.empty)
  else Loaded(page, size, 0.to(size).map(x => s"element $x"))
}

def consume(page: Int, size: Int): Observable[Event] = {
  Observable
    .interval(0.seconds)
    .scanEvalF(getPaginatedResource(page, size)) { (xs, _) =>
      getPaginatedResource(xs.page + 1, xs.size + 5)
    } // will emit items on each step
    .takeWhileInclusive(_.items.nonEmpty) // only take until list is empty
}

consume(0, 5)
  .foreachL(println)
  .runToFuture