Scala remote actors on same machine - scala

I am new to scala and trying to use the Actor model.
I have worked my way with using actors on the same machine.
Now, I want to use remote actors to go a step further.
As I have only one box to play with, I am planning to start a scala process which will act as a remote actor
remote.scala looks like
import scala.actors._
import scala.actors.remote._
import scala.actors.remote.RemoteActor._
import Actor._
import scala.math._
class remoteActor extends Actor{
def act(){
alive(9010)
register('myActor, self)
while (true)
{
println("Started Remote Actor")
receive {
case (caller :Actor, index :Int, length :Int) =>
{ // Do some stuff
}
}
}
}
}
object hello {
def main(args: Array[String]): Unit = {
println("Hello")
val act = new remoteActor
act.start
}
}
The main program which will use this remote actor
actor.scala
import scala.actors._
import scala.actors.remote._
import scala.actors.remote.RemoteActor._
import Actor._
class masterActor extends Actor{
def act()
{
val myRemoteActor = select(Node("localhost", 9010), 'myActor)
myRemoteActor ! (self,3,2)
}
}
object hello {
def main(args: Array[String]): Unit = {
val sample = new masterActor
sample.start
}
}
The problem is when I run remote.scala using eclipse (by installing the scala plugin for eclipse) I get the
Hello
Started Remote Actor
message printed in the eclipse console.
But when I run the same program from Windows command line after installing scala.
C:\Program Files (x86)\scala\bin>scala remote.scala
then the messages do not get printed. However, if I change the remote.scala file to
just include the hello world message, (i.e. remote.scala looks like)
object hello {
def main(args: Array[String]): Unit = {
println("Hello")
}
}
then the Hello message gets printed on the Windows command prompt.
Why is Windows command prompt not printing the messages in case of original remote.scala?
What I want is to start this scala process where the remote actor is registered and the process is still alive. I then want to start the main.scala program from another command prompt so that it sends messages to the remote actor to perform the computations.
How can I make sure that the remote actor is still alive and registered and the process is running?

Don't include the actor reference in your message. The receiving pattern should be:
receive {
case (index :Int, length :Int) =>
{ // Do some stuff
}
}
And the message should be sent as myRemoteActor ! (3,2)
In the receiver you can just write sender to refer to the original message sender. There are other useful functions, e.g. reply(msg) - replies to the original sender with msg

Related

Play! scala and Akka: how to test if an actor A sent a message to an actor B?

I want to test that an actor A send a message to an actor B after have received a message.
I'm using Play! 2.5 and I use the factories since I need to inject some of my classes and things like wSClient inside the actors.
The Actor A looks like:
object ActorA {
trait Factory {
def apply(ec: ExecutionContext, actorBRef: ActorRef): Actor
}
}
class ActorA #Inject()(implicit val ec: ExecutionContext,
#Named("actor-b") actorBRef: ActorRef)
extends Actor with ActorLogging with InjectedActorSupport {
override def receive: Receive = {
case i: Long =>
log info s"received $i"
actorBRef ! (i+1)
}
And the actor B is even more simple:
object ActorB {
trait Factory {
def apply(): Actor
}
}
class ActorB extends Actor with ActorLogging {
override def receive: Receive = {
case _ =>
log error "B received an unhandled message"
}
}
But my test doesn't pass, it is said that the expected message doesn't arrive, I get a Timeout in the test (but it is well logged by the actor B) so the problem comes from the test (and probably the Probe).
Here is the test:
val actorBProbe = TestProbe()
lazy val appBuilder = new GuiceApplicationBuilder().in(Mode.Test)
lazy val injector = appBuilder.injector()
lazy val factory = injector.instanceOf[ActorA.Factory]
lazy val ec = scala.concurrent.ExecutionContext.Implicits.global
lazy val factoryProps = Props(factory(ec, actorBProbe.ref))
val ActorARef = TestActorRef[ActorA](factoryProps)
"Actor B" must {
"received a message from actor A" in {
ActorARef ! 5L
actorBProbe.expectMsg(6L)
}
}
I also created a minimum Play! application with the code above available here.
In your test, actorBProbe is not the ActorB ref passed to ActorA constructor (of ref ActorARef). What really happens is that Guice creates a different ActorB (named actor-b), and passes its ref to ActorA (of ref ActorARef) constructor.
The test ends up with ActorB actor-b receiving 6L (as evident in log). While actorBProbe receives nothing.
The confusion really comes from mixing Guice lifecyle with Actors. In my experience, it creates more pains than I can bear.
To prove, simply print hash code of ActorRef's, you'll see they are different. Illustrated as followings:
val actorBProbe = TestProbe()
println("actorBProbe with ref hash: " + actorBProbe.ref.hashCode())
And,
class ActorA ... {
override def preStart =
log error "preStart actorBRef: " + actorBRef.hashCode()
// ...
}
In fact, even ec inside ActorA is not the same ec in the test code.
The following is a way to "force" the test to pass and at the same time prove that actorBProbe wasn't really being used by ActorB.
In stead of relying on Guice to "wire in" ActorB, we tell Guice to leave it alone by replacing #Named("actor-b") with #Assisted, like this,
import ...
import com.google.inject.assistedinject.Assisted
class ActorA #Inject()(...
/*#Named("actor-b")*/ #Assisted actorBRef: ActorRef)
...
Re-run the test, it'll pass. But this is probably not what you wanted to begin with.

How to make tests on akka actors response?

I am trying to understand the akka-Testkit", and hope it is ok to ask about it.
I found some tutorials and blogs that either access a state- or a lastMsg- attribute on the underlyingActor on the TestActorRef. However, a TestActorRef from the the "akka-testkit_2.11" % "2.4.10" does not have these attributes. I looked at the example on the akka website, and maybe I am missing something, but they show testing of among other an echo actor, but not with any simple actor implementations.
So, could someone help me understand how to test a worker that will respond with the same number if n % 3 == 0 (which is the case in the example). I would prefer not to use a future and the ask pattern if possible, and would like to make a test on the response that the actor will give (from that actors perspective by accessing its state or something similar).
class ProjectEulerScalaTestAkka extends TestKit(ActorSystem("testing")) with WordSpecLike with MustMatchers {
"A simple actor" must {
val actorRef = TestActorRef[Worker]
"receive messages" in {
actorRef ! 3
actorRef.underlyingActor.state//must not equal("world")
}
}
}
related:
How do I test an Akka actor that sends a message to another actor?
For now I am using a synchronized testing approach;
import akka.actor.ActorSystem
import akka.testkit.{TestActorRef, TestKit}
import org.scalatest.Matchers
import org.scalatest.WordSpecLike
import akka.pattern.ask
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.Success
class ProjectEulerScalaTestAkka extends TestKit(ActorSystem("testing")) with WordSpecLike with Matchers {
implicit val time = akka.util.Timeout(100 seconds)
"A simple actor" must {
val actorRef = TestActorRef[Worker]
"receive messages" in {
val f = (actorRef ? 3).asInstanceOf[Future[Int]]
val reply = f.value.get
reply should equal (Success(3))
}
}
}
What I did was mock the interface of the Actor that I was sending the message to, capturing the message and sending back a success message to the testActor reference.
success object with the captured message payload
case class SuccessWith(capturedMessage:Any = null)
a mock actor that you send your message to which, in turn, returns some value to the test actor
case class MockActor(requester: ActorRef) extends Actor {
override def receive: Receive = {
case i: Int => {
requester ! i
}
}
}
set up the actor you're wanting to unit test
val actorRef = system.actorOf(Props(new YourActor(args)))
and then your test
"A simple actor" must {
"receive messages" in {
val f = actorRef ! 3
expectMsg(Success(3))
}
}
}

Can not always reuse Actor's name after graceful stop

I studied Akka's "Graceful Stop" for actors and created a small test app to test it.
Application shows that "Graceful Stop" mentioned in http://doc.akka.io/docs/akka/snapshot/scala/actors.html#Graceful_Stop
does not always guarantee that you can reuse the gracefully stopped Actor's name.
Every now and then the following exception appears:
Exception in thread "main" akka.actor.InvalidActorNameException: actor name [DummyActor] is not unique!
Why is that? How can I fix the app so that InvalidActorNameExceptions would not appear every now and then?
Here is the code:
main class...
import akka.actor._
import akka.pattern.gracefulStop
import DummyActor.Stop
import DummyActor
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
object AkkaTest {
def main(args: Array[String]) {
val actorsystem = ActorSystem("testSystem")
1 to 5 foreach { _ =>
// Create an actor with name: DummyActor
val dummyActor = actorsystem.actorOf(Props[DummyActor], "DummyActor")
// Gracefully stop the DummyActor
val stopped: Future[Boolean] = gracefulStop(dummyActor, 5 seconds, Stop)
Await.result(stopped, 6 seconds)
}
val terminated: Future[Terminated] = actorsystem.terminate()
Await.result(terminated, 10 seconds)
System.out.println("Finished successfully. Try again, eventually it will fail. You can also increase the amount of loops.")
}
}
and the actor...
import akka.actor.Actor
import DummyActor.Stop
object DummyActor {
case object Stop
}
class DummyActor extends Actor {
override def receive: Receive = {
case Stop => context stop self
}
}
I have Scala 2.11.7 and with Java 8 and Akka 2.4.0.
Commend has awfull formatting so, i'll copy it here
I just followed the link and found red alert here
Warning
Keep in mind that an actor stopping and its name being deregistered
are separate events which happen asynchronously from each other.
Therefore it may be that you will find the name still in use after
gracefulStop() returned. In order to guarantee proper
deregistration, only reuse names from within a supervisor you control
and only in response to a Terminated message, i.e. not for top-level
actors.
So make supervisor actor and start namesake only on Terminated reception

Code not running when main method is added

I',m following the akka tutorial from http://doc.akka.io/docs/akka/2.2.0/AkkaScala.pdf and below is the HelloWorld program. The main method is added by me but the I do not receive the "run as scala application" in Eclipse when I attempt to run it. According to the doc to run the program from the command line : "java -classpath akka.Main com.example.HelloWorld" but I require to run it from Eclipse so have added my own main method. Why will the below code not run ?
import akka.actor.Actor
import akka.actor.Props
class HelloWorld extends Actor {
override def preStart(): Unit = {
// create the greeter actor
val greeter = context.actorOf(Props[Greeter], "greeter")
// tell it to perform the greeting
greeter ! Greeter.Greet
}
def receive = {
// when the greeter is done, stop this actor and with it the application
case Greeter.Done => context.stop(self)
}
object Greeter {
def main(args: Array[String]) {
new HelloWorld
}
case object Greet
case object Done
}
class Greeter extends Actor {
def receive = {
case Greeter.Greet =>
println("Hello World!")
sender ! Greeter.Done
}
}
}
A main method has to be within a standalone object. Here you have it within an object within a class.

Scala Actor in script mode

I'm trying go through Chapter 9 of Programming in Scala, but I found the Actor sample code could not run in script mode.
The code is simple:
// TestActor.scala
import scala.actors.Actor
class Redford extends Actor {
def act() {
println("A lot of what acting is, is paying attention.")
}
}
val robert = new Redford
robert.start
But when I run scala TestActor.scala, nothing happens, the program exit before the Redford class print anything.
But if I use the following code to compile and run, everything works fine, it prints the message as expected.
// TestActorCompiled.scala
import scala.actors.Actor
class Redford extends Actor {
def act() {
println("A lot of what acting is, is paying attention.")
}
}
object Main {
def main (args: Array[String]) {
val robert = new Redford
robert.start
}
}
It seems when the program run in the script mode, it exit before the actor doing anything.
Why this happens? And how could I make this program do no exit before Actor.act() is done when the program is running in script mode?
Update:
I'm using Scala 2.8.1.final
Tested on 2.8.1.final. Strange thing. The first time I run it failed with:
Could not connect to compilation daemon.
Exception in thread "main" java.lang.Exception: fsc failure
at scala.tools.nsc.CompileSocket.fatal(CompileSocket.scala:50)
at scala.tools.nsc.CompileSocket.getPort(CompileSocket.scala:122)
at scala.tools.nsc.CompileSocket.getsock$1(CompileSocket.scala:152)
at scala.tools.nsc.CompileSocket.getOrCreateSocket(CompileSocket.scala:170)
at scala.tools.nsc.ScriptRunner$.compileWithDaemon(ScriptRunner.scala:145)
at scala.tools.nsc.ScriptRunner$.compile$1(ScriptRunner.scala:197)
at scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:225)
at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:265)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:91)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
The second time it passed successfully:
>scala TestActor.scala
A lot of what acting is, is paying attention.