【问题标题】:Porting simple Scala remote actor example to Akka actors将简单的 Scala 远程 Actor 示例移植到 Akka Actor
【发布时间】:2011-10-07 21:27:10
【问题描述】:

我尝试将 this simple actor example 从 Scala 演员发送“Ping”和“Pong”转移到 Akka 演员,但我不断收到错误,我想知道这只是一个简单的错误还是一些根本性的错误。

考虑这段代码:

import akka.actor.Actor._
import akka.actor.Actor

case class Message(text: String)

class PingPongActor(name: String) extends Actor {

  def receive = {
      case Message(msg) =>
        println("received: " + msg)
        Thread.sleep(1000)
        self.reply(Message("Ping"))
      case None => println("ping: timed out!")
  }
}

object Ping extends App {
  remote.start("localhost", 2552)
        .register("ping-service", actorOf(new PingPongActor("pong")))

  val actor = remote.actorFor("ping-service", "localhost", 2552)

  actor ! (Message("Ping"))
}

object Pong extends App {
  remote.start("localhost", 2553)
        .register("pong-service", actorOf(new PingPongActor("ping")))

  val actor = remote.actorFor("pong-service", "localhost", 2553)

  actor ! (Message("Pong"))
}

我不断收到此错误:

received: Ping
[GENERIC] [07.10.11 23:18] [RemoteServerStarted(akka.remote.netty.NettyRemoteSupport@3ff2cea2)]
[ERROR]   [07.10.11 23:18] [akka:event-driven:dispatcher:global-2] [LocalActorRef] 
   No sender in scope, can't reply.
   You have probably:
      1. Sent a message to an Actor from an instance that is NOT an Actor.
      2. Invoked a method on an TypedActor from an instance NOT an TypedActor.
   You may want to have a look at safe_! for a variant returning a Boolean
akka.actor.IllegalActorStateException: 
   No sender in scope, can't reply.
   You have probably:
      1. Sent a message to an Actor from an instance that is NOT an Actor.
      2. Invoked a method on an TypedActor from an instance NOT an TypedActor.
   You may want to have a look at safe_! for a variant returning a Boolean
[laptop_e3263500-f129-11e0-a78d-001636ff8076]
    at akka.actor.NullChannel$.$bang(Channel.scala:177)
    at akka.actor.ActorRef$class.reply(ActorRef.scala:398)
    at akka.actor.LocalActorRef.reply(ActorRef.scala:605)
    at PingPongActor$$anonfun$receive$1.apply(RemoteActor.scala:21)
    at PingPongActor$$anonfun$receive$1.apply(RemoteActor.scala:15)
    at akka.actor.Actor$class.apply(Actor.scala:545)
    at PingPongActor.apply(RemoteActor.scala:13)

我的想法是我启动了两个应用程序,Ping 和 Pong,它们尝试每秒互相发送一条消息并在终端上打印(或者如果两个都没有收到消息,则打印一条错误消息秒)。

【问题讨论】:

  • 嗯...错误消息表明您已从不是演员的实例向演员发送了消息。在担心远程方面之前,您不需要先解决这个问题吗?

标签: scala networking akka actor


【解决方案1】:

您的代码最大的根本问题是您从演员外部发送消息,因此响应无处可去。您会注意到在原始示例中,初始的Message("ping") 是从Ping 演员的act() 循环内发送的。但实际上你有几个问题,最好重新开始,稍微重构一下代码。这是一个有效的示例,但它取决于以特定顺序启动客户端。当然,您可以重写它以继续重试来自 PingActor 的连接等。

sealed trait Message
case class Ping extends Message
case class Pong extends Message

class PingActor extends Actor {

  override def preStart = {
    val pong = remote.actorFor("pong-service", "localhost", 2553)
    pong ! Ping
  }

  def receive = {
    case Pong => {
      println("Received pong")
      Thread.sleep(1000)
      self.reply(Ping)
    }
  }
}

class PongActor extends Actor {
  def receive = {
    case Ping => {
      println("Received ping")
      Thread.sleep(1000)
      self.reply(Pong)
    }
  }
}

object pingApp extends App {
  val actor = actorOf(new PingActor)
  remote.start("localhost", 2552)
        .register("ping-service", actor)
}

object pongApp extends App {
  val actor = actorOf(new PongActor)
  remote.start("localhost", 2553)
        .register("pong-service", actor)
}

【讨论】:

  • 我是否需要像在 Scala 演员中一样在演员内部或外部实施“等待并重试,直到另一个演员出现”-循环?
  • 嗯,这完全取决于您以及您想要如何设计事物。关键是 PingActor 必须能够获取对远程 PongActor 的初始引用,因此如果您将重试逻辑放在 actor 之外,则需要将引用传递给 PingActor。这可以通过消息轻松完成。
猜你喜欢
  • 2014-11-10
  • 2013-02-02
  • 1970-01-01
  • 2013-10-03
  • 2016-08-21
  • 2015-09-09
  • 1970-01-01
  • 2019-04-11
  • 1970-01-01
相关资源
最近更新 更多