我有一个API
,它会返回Future
。现在为其中一个用例引入Actor
并尝试继续使用相同的服务API
。从下面您可以看到MyService.saveValues
返回未来。
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
}
}
正如您在def saveMessage
中所看到的,我正在使用ask
等待演员的结果。但是,ask
也会创建自己的未来,因此val res
中的结果(saveMessage
)变为Future[Future[T]]
,这看起来很烦人。处理这种情况的最佳方法是什么?
答案 0 :(得分:7)
pipeTo
将未来的结果转发给ActorRef
。
import akka.pattern.pipe
val originalSender = sender
val res : Future[\/[Throwable,String] ] = MyService.saveValues(list)
res pipeTo originalSender
如果saveValues
抛出,你的未来永远不会完成,但最终还会计划出来。
如果您最终得到Future[Future[A]]
,但由于Future[A]
或某事需要sequencing/traversing
,您可以随时“flatMap that that shit。”
import ExecutionContext.Implicits.global
val foo: Future[Future[Int]] = ???
val bar: Future[Int] = foo.flatMap(identity)
如果你已经依赖scalaz(以及scalaz.contrib,如果在scalaz 7.0.x上),你可以使用monad语法中定义的join
。
import scalaz.syntax.monad._
import scalaz.contrib.std.scalaFuture._
val bar2: Future[Int] = foo.join