I have an existing API
which returns a Future
. Now introducing an Actor
for one of the use cases and trying to continue using same service API
from it. From below you can see MyService.saveValues
return future.
object MyActor {
implicit val ec = scala.concurrent.ExecutionContext.Implicits.global
implicit val timeout = Timeout(1 second)
case class SampleMessage(list: List[String])
val actorSystem = //get actorSystem that was created at the startup
def saveMessage(list: List[String]) ={
val res = (actorSystem.actorOf(Props[MyActor]) ? SaveMyMessage(list) ).mapTo[Future[\/[Throwable,String]]
//res map{ r=>
//}
}
}
class MyActor extends Actor {
import MyActor._
def receive = {
case SaveMyMessage(list) =>
val originalSender = sender
val res : Future[\/[Throwable,String] ] = MyService.saveValues(list)
originalSender ! res
}
}
As you can see in def saveMessage
I am using ask
to wait for a result from an actor. However ask
also creates its own future so result (val res
) in saveMessage
becomes Future[Future[T]]
which looks annoying. What's the best way to deal with this scenario?
pipeTo
forwards the result of a Future to an ActorRef
.
import akka.pattern.pipe
val originalSender = sender
val res : Future[\/[Throwable,String] ] = MyService.saveValues(list)
res pipeTo originalSender
If saveValues
throws, your future never complete and will end up timing something out though.
If you ever end up with Future[Future[A]]
, but want Future[A]
as a result of sequencing/traversing
or something, you can always "flatMap that shit."
import ExecutionContext.Implicits.global
val foo: Future[Future[Int]] = ???
val bar: Future[Int] = foo.flatMap(identity)
If you already depend on scalaz (and scalaz.contrib if on scalaz 7.0.x), you can use join
defined in monad syntax.
import scalaz.syntax.monad._
import scalaz.contrib.std.scalaFuture._
val bar2: Future[Int] = foo.join
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With