链接Akka Actor Ask电话的正确方法是什么?

时间:2014-04-02 04:32:19

标签: scala playframework akka

我在scala中使用Play Framework。我是scala,akka和play的新手。

这是我的演员系统。我不确定我做得对,但我有两台路由器。演员A为1,演员B为1:

  val system = ActorSystem("ActionSystem")
  val actorARouter = system.actorOf(Props[ActionParser].withRouter(
    SmallestMailboxRouter(Runtime.getRuntime.availableProcessors())), name = "actorARouter")
  val actorBRouter = system.actorOf(Props[ActionDispatcher].withRouter(
    SmallestMailboxRouter(Runtime.getRuntime.availableProcessors())), name = "actorBRouter")

这是我目前的设置: play框架为我提供了一个Controller,它接收一个带有json的http rest调用。每当Controller收到一个休息呼叫时,我都会把json发送给一个路由器,用于演员A.这就是看起来的样子:

(actorARouter ? request.body.asJson.get).map {
      case m: controllers.HttpMessages.OK => Ok(m.body)
      case m: controllers.HttpMessages.HttpResponse => Status(m.status)(m.body)
    }

Actor A然后将json解析为Seq of objects,然后通过ask向Actor B发送它们。Actor B应该最终通过将它们发送给其他actor来处理它们,但是现在只是返回泛型响应。 / p>

ActorA通过将来接收通用响应,然后解析为JSON,然后通过OK响应返回到Controller ......或者至少是应该发生的事情。

发生了什么: 所以发生的事情是控制器发送给ActorA,ActorA发送给ActorB。 ActorB向ActorA发送通用响应。 ActorA将通用响应解析为JSON并尝试执行sender ! OK(json)但是我在控制台中收到一条消息,说它没有被传递,因为它是一封死信"。当我查看发件人时调试它,发件人是对演员akka://ActionSystem/deadLetters

的引用

我的问题:

  1. 显然我做错了什么。也许我不应该像这样将这些演员的回应链接在一起。再一次,我提到我只有计划通过让ActorB向其他演员发出请求来进一步推动这一点。
  2. 当我在一个演员身上做一个问题时,那个不会占用该线程并阻止它处理其他消息的同时它正在等待响应吗?
  3. 修改 我发现我可以保存对发件人的引用供以后使用,然后发送给它,这似乎解决了死信问题。但我仍然很不确定这是否是正确的做事方式。感觉就像每次我添加另一层演员时,我的响应时间增加了10毫秒。也许这可能是由于其他因素造成的。

1 个答案:

答案 0 :(得分:3)

如果没有查看你的代码,我就无法评论导致死信的原因,从你的编辑我猜你关闭sender()而不是将其分配给变量并关闭它。

回答你的问题:

  1. 如果您只使用“即发即弃”消息,则可以更轻松地使用actor构建消息流。问题模式在某些情况下很有用,但大多数情况下你应该尽量避免使用它。您可以做的是使用forward代替tell将原始发件人传递给您的演员。这样,消息流中的最后一个actor就可以生成响应。第一个actor只需要代码来处理响应,而不需要关心生成响应。在那里很好地分离了关注点。如果您需要聚合多个响应以便之后发送单个响应,您还可以使用临时演员,所有其他演员将发送他们的响应,并且知道发送者。临时演员在完成工作后需要停止。
  2. 据我所知,ask模式是异步的,并在内部使用临时actor。但是,如果您在actor中等待未来的结果,那将阻止该actor,并且它将无法处理更多消息。使用ask模式的好方法是与pipeTo Pattern结合使用,您可以使用它将ask的结果发送给actor(通常为self