Porting a simple Scala remote actor example to Akki actors

I am trying to convey this simple example of an actor sending “Ping” and “Pong” from Scala actors to Akka actors, but I keep getting errors, and I wonder if this is just a simple error or some kind of fundamental error.

Consider this code:

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

I keep getting this error:

 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) 

The idea is that I run two applications: Ping and Pong , which try to send a message to each other every second and print it on the terminal (or print an error message if the message is not received in two seconds).

+4
source share
1 answer

The biggest problem with your code is that you are sending a message from outside the actor, and so the answer does not take place. In the original example, you will notice that the initial Message("ping") sent from the act() loop of the Ping actor. But actually you have a couple of questions, and it’s better to start by rebuilding the code a bit. Here is an example that works, but it depends on starting clients in a specific order. Of course, you can rewrite this to, among other things, retry connecting to 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) } 
+6
source

All Articles