什么是Akka类型的pipeTo?

时间:2018-05-03 18:29:23

标签: scala akka akka-typed

我目前正在尝试将现有的无类型演员重写为键入的演员。由于演员正在使用ScalikeJDBC与MySQL数据库交谈,并且由于我想异步完成,我正在处理来自单独(非演员)存储库类的Futures。

对于无类型的Akka,在演员的接收方法中,我可以这样做:

import akka.pattern.pipe
val horseList : Future[Seq[Horse]] = horseRepository.listHorses(...)
horseList pipeTo sender()

发件人演员最终会收到一份马匹清单。我无法弄清楚如何在行为中执行此操作,例如:

val behaviour : Behavior[ListHorses] = Behaviors.receive { 
    (ctx,msg) => msg match {
        case ListHorses(replyTo) => 
            val horseListF : Future[Seq[Horse]] = horseRepository.listHorses(...)
            // -> how do I make horseListF's content end up at replyTo? <-
            Behaviors.same
    }
}

管道模式不起作用(因为它需要一个无类型的ActorRef),到目前为止,我还没有在akka-actor-typed(2.5.12)依赖项中找到任何其他东西,我正在使用它来完成这项工作

我该怎么做?

3 个答案:

答案 0 :(得分:0)

为什么不使用未来的回调来发送回信息?检查一下这个例子,也许你可以使用simliar近似值:

import akka.NotUsed
import akka.typed.{ActorRef, ActorSystem, Behavior}
import akka.typed.scaladsl.Actor

import scala.concurrent.{Await, Future}
import scala.util.{Failure, Success}
import scala.concurrent.ExecutionContext.Implicits.global

sealed trait Response
case class Message(msg: String) extends Response

case class Greet(whom: String, replayTo: ActorRef[Response])

object Methods {
  def GetRecipient : Future[String] = Future { "Me" }
}

object Greeter {
  import Methods._
  import akka.typed.scaladsl.Actor

  val behavior =
    Actor.immutable[Greet] { (ctx, greet) =>
      println(greet)
      GetRecipient onComplete {
        case Success(str) => {
          // Use the future call back instad the pipeTo
          greet.replayTo ! Message("Hi!")
        }
        case Failure(err) => greet.replayTo ! Message("Error")
      }
      Actor.same
    }
}

object Man extends App {

  import Greeter._
  import scala.concurrent.duration._

  val main: Behavior[Response] = {
    Actor.deferred[Response] { ctx =>
      val enricherRef = ctx.spawn(behavior, "greet")
      enricherRef ! Greet("hey", ctx.self)

      Actor.immutable[Response] {
        case (ctx, m: Response) => {
          println(m)
          Actor.same
        }
      }
    }
  }

  val system = ActorSystem( "GreetDemo", main)

  Thread.sleep(5000)
}

此示例仅向新生成的actor发送消息,但在您的情况下,我会为每个查询使用新的actor。

答案 1 :(得分:0)

您可以在未来成功完成后直接向replyTo发送消息:

case ListHorses(replyTo) => 
    horseRepository.listHorses(...) foreach { horses => replyTo ! horses }
    Behaviors.same

或者如果您也想处理错误:

case ListHorses(replyTo) =>
    horseRepository.listHorses(...) onComplete { 
        case Success(horses) => replyTo ! horses
        case Failure(e) => // error handling 
    }
    Behaviors.same

为此,您需要一个ExecutionContext。通常,与演员使用相同的角色是合理的,因此您必须首先使其可用于onCompleteforeach

implicit val ec = ctx.executionContext

答案 2 :(得分:0)

在Akka 2.5.22(可能更早)中,有context.pipeToSelf

  def pipeToSelf[Value](future: Future[Value])(mapResult: Try[Value] => T): Unit

您仍然必须提供SuccessFailure的模式匹配,在我的代码中,我已经用这种糖简化了这些匹配:

def mapPipe[A, T](success: A => T, failure: Throwable => T): Try[A] => T = {
  case Success(value) => success(value)
  case Failure(e) => failure(e)
}

导致这样的通话:

case class Horses(horses: Seq[Horse]) extends Command
case class HorseFailure(e: Throwable) extends Command

...

context.pipeToSelf(horseList) {
  mapPipe(Horses,HorseFailure)
}