2

I'm trying to wrap some blocking calls in Future.The return type is Seq[User] where User is a case class. The following just wouldn't compile with complaints of various overloaded versions being present. Any suggestions? I tried almost all the variations is Source.apply without any luck.

// All I want is Seq[User] => Future[Seq[User]]

def findByFirstName(firstName: String) = {
  val users: Seq[User] = userRepository.findByFirstName(firstName)

  val sink = Sink.fold[User, User](null)((_, elem) => elem)

  val src = Source(users) // doesn't compile

  src.runWith(sink)
}
Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219

2 Answers2

6

First of all, I assume that you are using version 1.0 of akka-http-experimental since the API may changed from previous release.

The reason why your code does not compile is that the akka.stream.scaladsl.Source$.apply() requires scala.collection.immutable.Seq instead of scala.collection.mutable.Seq.

Therefore you have to convert from mutable sequence to immutable sequence using to[T] method.

Document: akka.stream.scaladsl.Source

Additionally, as you see the document, Source$.apply() accepts ()=>Iterator[T] so you can also pass ()=>users.iterator as argument.

Since Sink.fold(...) returns the last evaluated expression, you can give an empty Seq() as the first argument, iterate over the users with appending the element to the sequence, and finally get the result.

However, there might be a better solution that can create a Sink which puts each evaluated expression into Seq, but I could not find it.

The following code works.

import akka.actor._
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Source,Sink}
import scala.concurrent.ExecutionContext.Implicits.global

case class User(name:String)

object Main extends App{
    implicit val system = ActorSystem("MyActorSystem")
    implicit val materializer = ActorMaterializer()
    val users = Seq(User("alice"),User("bob"),User("charlie"))

    val sink = Sink.fold[Seq[User], User](Seq())(
      (seq, elem) => 
        {println(s"elem => ${elem} \t| seq => ${seq}");seq:+elem})

    val src = Source(users.to[scala.collection.immutable.Seq])
    // val src = Source(()=>users.iterator) // this also works

    val fut = src.runWith(sink) // Future[Seq[User]]
    fut.onSuccess({
      case x=>{
        println(s"result => ${x}")
      }
    })
}

The output of the code above is

elem => User(alice)     | seq => List()
elem => User(bob)       | seq => List(User(alice))
elem => User(charlie)   | seq => List(User(alice), User(bob))
result => List(User(alice), User(bob), User(charlie))
ymonad
  • 11,710
  • 1
  • 38
  • 49
  • Yes I'm using version 1.0. And your answer is exactly what I was looking for. It continues to amuse me that some people just don't answer the question asked before they make alternative suggestions. If it's any consolation, apparently I'm not the first one to have tripped over the case that `Seq` as defined in the package object scala is *not* an alias for the immutable version. [Here's](https://groups.google.com/forum/#!topic/scala-internals/g_-gIWgB8Os) a big discussion about that involving Martin Odersky. – Abhijit Sarkar Sep 10 '15 at 19:45
3

If you need just Future[Seq[Users]] dont use akka streams but futures

import scala.concurrent._
import ExecutionContext.Implicits.global
val session = socialNetwork.createSessionFor("user", credentials)
val f: Future[List[Friend]] = Future {
  session.getFriends()
}
al32
  • 109
  • 3
  • Where's the concurrency control, exception handling, logging that Akka so beautifully provides? Plus I'm using `akka-http` for my resource, I already have Akka Streams, might as well put it to use. – Abhijit Sarkar Sep 10 '15 at 07:36
  • Using `Future`s seems to be more appropriate for `userRepository` or any other repository. The reason why is that your repository represents some kind of querying mechanism and it returns your data as a whole. Whereas, streams should be used in places where data is coming in chucks or smaller portions and may be infinitely provided. – Ivan Stanislavciuc Sep 10 '15 at 11:23
  • @VanyaStanislavciuc Nothing in the Reactive Streams spec or Akka Streams says that a stream needs to be infinite or chunked. A chunked stream is a use case, not a necessity. Besides, even though I'm just passing through the `Seq` now, I might very well add some processing logic in the future. It is always better to design for the future, especially when the tools are already available. – Abhijit Sarkar Sep 10 '15 at 19:53