简体   繁体   English

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

[英]Does the ask pattern work with Akka IO actors?

Say I have an IO Actor connection capable of sending and receiving messages over TCP. 假设我有一个能够通过TCP发送和接收消息的IO Actor connection In my actor, I ask the other side of the connection for a response: 在我的演员中,我向连接的另一方询问响应:

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

It appears that with this code the ask future times out, and instead the containing actor receives the raw message outside of the ask pattern. 看来,使用此代码,ask将会超时,而包含的actor会在ask模式之外接收原始消息。

Can you use the ask pattern with Akka IO actors? 你能和Akka IO演员一起使用ask模式吗? If not, why not? 如果没有,为什么不呢?

I don't know the architecture in detail, but here's how I would explain it to myself: 我不太详细地了解这个架构,但这是我如何向自己解释的:

The problem with Akka IO connector actors here is that they don't work in a request-response manner. Akka IO连接器actor的问题在于它们不能以请求 - 响应方式工作。 And if you think about it - that makes sense, because TCP is not a request-response protocol. 如果你考虑一下 - 这是有道理的,因为TCP不是一个请求 - 响应协议。 TCP doesn't even have a notion of message . TCP甚至没有消息的概念。 From programmer's perspective TCP connection is just a pair of continuous byte streams - one in each direction. 从程序员的角度来看,TCP连接只是一对连续的字节流 - 每个方向一个。 That's it. 而已。

Akka IO is a minimal actor layer on top of network protocols, so it's not surprising that it mimics this behaviour. Akka IO是网络协议之上的最小角色层,因此它模仿这种行为就不足为奇了。 When TCP actor receives some data from the network, it only knows one thing - that it should send a Received message to the actor that originally sent the Connect message. 当TCP actor从网络接收一些数据时,它只知道一件事 - 它应该向最初发送Connect消息的actor发送Received消息。 That's all. 就这样。 It has no idea that the data it received from the network is somehow related to the data that you sent earlier. 它不知道从网络收到的数据与您之前发送的数据有某种关联。

Adding to all of that, ask pattern works only under assumption that when you send message A to some actor, it will respond with the message B by sending it exactly to the sender of message A . 除此之外,只有在假设当您向某个actor发送消息A时,才会ask模式,它会通过将消息B发送给消息A发送者来响应消息B As we already know, TCP actor doesn't do that - it simply sends everything to the sender of original Connect message. 正如我们已经知道的那样,TCP actor不会这样做 - 它只是将所有内容发送给原始Connect消息的发送者。

The reason why this assumption is required is that ask pattern actually creates some sort of a "phantom" actor that is set as the sender of the message sent using ask . 需要这种假设的原因是, ask模式实际上创建了某种“幻像”actor,它被设置为使用ask 发送的消息的发送 This "phantom" actor will then receive the response and invoke all the callbacks registered on the Future . 然后,这个“幻影”演员将收到响应,并调用在Future上注册的所有回调。 As a side note - be aware that those callbacks are invoked completely independently of the sending actor, ie they may run concurrently to it! 作为旁注 - 请注意,这些回调完全独立于发送方调用,即它们可以同时运行!

So, I would finally conclude that the ask pattern used like this will not work with Akka IO, because it's simply too low level for such an abstraction. 所以,我终于得出结论, ask使用这样的格局不会与阿卡IO工作,因为它只是等级太低了这样的抽象。 If you still want it, you need to create you own layer of abstraction on top of Akka IO, eg some simple intermediate actor that covers TCP connector actor and implements the request-response behaviour. 如果你仍然需要它,你需要在Akka IO之上创建自己的抽象层,例如一些简单的中间actor,它涵盖TCP连接器actor并实现请求 - 响应行为。

As an additional reference to @ghik's answer, here's roughly how I created an intermediate actor to enable the ask pattern for IO on the rest of my actors. 作为@ ghik答案的另一个参考,这里大致是我如何创建一个中间actor来为其余的actor启用IO的ask模式。

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)
   }
}

Instances of this class can be ask ed for responses. 可以ask此类的实例以获取响应。 Note that I have only tested this with one simultaneous asker (which is my use case) and this probably doesn't work for multiple askers. 请注意,我只使用一个同时提问者(这是我的用例)对此进行了测试,这可能不适用于多个请求者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM