问题模式是否适用于Akka IO演员?

时间:2014-05-09 16:04:03

标签: scala akka

假设我有一个能够通过TCP发送和接收消息的IO Actor connection。在我的演员中,我问连接的另一方是否有回应:

 connection.ask(ByteString("stuff")).collect {
    case Received(response) => log.debug(response.utf8String)
 }

看来,使用此代码,ask将会超时,而包含的actor会在ask模式之外接收原始消息。

你能和Akka IO演员一起使用ask模式吗?如果没有,为什么不呢?

2 个答案:

答案 0 :(得分:2)

我不太详细了解这个架构,但是我会在这里向自己解释:

这里的Akka IO连接器演员的问题是他们不能以请求 - 响应的方式工作。如果你考虑一下 - 这是有道理的,因为TCP不是一个请求 - 响应协议。 TCP甚至没有消息的概念。从程序员的角度来看,TCP连接只是一对连续的字节流 - 每个方向一个。那就是它。

Akka IO是网络协议之上的最小角色层,因此它模仿这种行为并不奇怪。当TCP actor从网络接收一些数据时,它只知道一件事 - 它应该向最初发送Received消息的actor发送Connect消息。这就是全部。它不知道从网络收到的数据与您之前发送的数据有某种关系。

除此之外,ask模式仅在假设当您向某个actor发送消息A时才会起作用,它会通过将消息B发送到消息A发件人。我们已经知道,TCP演员不会这样做 - 它只是将所有内容发送给原始Connect消息的发件人。

需要这种假设的原因是ask模式实际上创造了某种类型的幻象"设置为使用ask发送的邮件的发件人的actor。这个"幻像"然后,actor将收到响应并调用Future上注册的所有回调。作为旁注 - 请注意,这些回调完全独立于发送方调用,即它们可以同时运行!

所以,我最后会得出结论,像这样使用的ask模式将与Akka IO一起工作,因为它对于这样的抽象来说太低了。如果您仍然想要它,您需要在Akka IO之上创建自己的抽象层,例如:一个简单的中间actor,它涵盖TCP连接器actor并实现请求 - 响应行为。

答案 1 :(得分:0)

作为对@ ghik回答的补充参考,这里大致说明了我是如何创建一个中间角色来为我的其他演员启用IO的问题模式。

class IOAskHandlerActor(address: InetSocketAddress) extends Actor {
   override def receive = {
      // Connection setup code omitted    
      case Connected(remote, local) =>
         // other code omitted
         context become latch(sender())
   }

   def latch(connection: ActorRef): Receive = {
      case outgoing =>
         context become receiving(connection, sender())
         connection ! MySerializer.write(outgoing)
   }

   def receiving(connection: ActorRef, asker: ActorRef): Receive = {
      case Received(incoming) =>
         context become latch(connection)
         asker ! MySerializer.read(incoming)
   }
}

此类的实例可以ask用于回复。请注意,我仅使用一个同时提问者(这是我的用例)对此进行了测试,这可能对多个问题无效。