使用Akka-IO TCP初始化akka actor

时间:2014-08-06 15:28:43

标签: scala akka akka-io

使用Akka-IO TCP,在actor中建立连接的过程如下:

class MyActor(remote: InetSocketAddress) extends Actor {

  IO(Tcp) ! Connect(remote)    //this is the first step, remote is the address to connect to

  def receive = {
    case CommandFailed(_: Connect) => context stop self // failed to connect

    case Connected(remote, local) =>
      val connection = sender()
      connection ! Register(self)
      // do cool things...  
  }
}

您向Connect发送了IO(Tcp)条消息,并希望收到CommandFailedConnected条消息。

现在,我的目标是创建一个包装TCP连接的actor,但是我希望我的actor只有在建立连接后才开始接受消息 - 否则,在等待Connected消息时它会开始接受查询,但没有人发送给他们。

我尝试了什么:

class MyActor(address: InetSocketAddress) extends Actor {

  def receive = {
    case Initialize =>
      IO(Tcp) ! Connect(address)
      context.become(waitForConnection(sender()))

    case other => sender ! Status.Failure(new Exception(s"Connection to $address not established yet."))
  }

  private def waitForConnection(initializer: ActorRef): Receive = {
    case Connected(_, _) =>
      val connection = sender()
      connection ! Register(self)
      initializer ! Status.Success(Unit)
      // do cool things

    case CommandFailed(_: Connect) =>
      initializer ! Status.Failure(new Exception("Failed to connect to " + host))
      context stop self
  }
}

我的第一个receive期待一条消息,它将触发整个连接过程,一旦Initialize的发送方收到成功消息并知道它可以知道开始发送查询。

我对此不太满意,它迫使我用

创建我的演员
Initialize

它不会非常"重启"友好。

在Tcp图层回复val actor = system.actorOf(MyActor.props(remote)) Await.ready(actor ? Initialize, timeout) 之前,是否有任何想法保证我的演员不会开始接收来自邮箱的邮件?

2 个答案:

答案 0 :(得分:4)

使用Stash特征来存储您目前无法处理的消息。当每个过早的消息到达时,使用stash()推迟它。连接打开后,使用unstashAll()将这些邮件返回邮箱进行处理。然后,您可以使用become()切换到消息处理状态。

答案 1 :(得分:1)

为了让您的演员更加友好地重新启动,您可以覆盖与演员生命周期相关的方法,例如preStartpostStopAkka documentation对演员的开始,停止和重启钩子有很好的解释。

class MyActor(remote: InetSocketAddress) extends Actor {

  override def preStart() {
    IO(Tcp) ! Connect(remote) 
  }

  ...
}

现在你可以用val actor = system.actorOf(MyActor.props(remote))开始你的演员了。它在启动时建立连接,并在重新启动时重新建立连接。