Портирование простого примера удаленного актера Scala для актеров Akka - PullRequest
4 голосов
/ 08 октября 2011

Я пытаюсь портировать этот простой пример актера отправки "Ping" и "Pong" от актеров Scala актерам 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, которые пытаются посылать друг другу сообщение каждую секунду и распечатывать его на терминале (или выводить сообщение об ошибке, если в течение двух секунд сообщение не получено).

1 Ответ

6 голосов
/ 08 октября 2011

Самая большая фундаментальная проблема с вашим кодом заключается в том, что вы отправляете сообщение извне субъекта, поэтому ответу некуда идти.В исходном примере вы заметите, что начальный Message("ping") отправляется из цикла act() актера Ping.Но на самом деле у вас есть пара проблем, и лучше начать все сначала, немного перестроив код.Вот пример, который работает, но это зависит от запуска клиентов в определенном порядке.Конечно, вы можете переписать это, чтобы, среди прочего, повторить попытку подключения из 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)
}
...