Scala Actor in script mode - scala

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.

Related

Failing a scalatest when akka actor throws exception outside of the test thread

I've had a situation come up and bite me a few times where I'm testing an Actor and the Actor throws an exception unexpectedly (due to a bug), but the test still passes. Now most of the time the exception in the Actor means that whatever the test is verifying won't come out properly so it the test fails, but in rare cases that's not true. The exception occurs in a different thread than the test runner so the test runner knows nothing about it.
One example is when I'm using a mock to verify some dependency gets called, and due to a mistake in the Actor code I call an unexpected method in the mock. That causes the mock to throw an exception which blows up the actor but not the test. Sometimes this can even cause downstream tests to fail mysteriously because of how the Actor blew up. For example:
// using scala 2.10, akka 2.1.1, scalatest 1.9.1, easymock 3.1
// (FunSpec and TestKit)
class SomeAPI {
def foo(x: String) = println(x)
def bar(y: String) = println(y)
}
class SomeActor(someApi: SomeAPI) extends Actor {
def receive = {
case x:String =>
someApi.foo(x)
someApi.bar(x)
}
}
describe("problem example") {
it("calls foo only when it receives a message") {
val mockAPI = mock[SomeAPI]
val ref = TestActorRef(new SomeActor(mockAPI))
expecting {
mockAPI.foo("Hi").once()
}
whenExecuting(mockAPI) {
ref.tell("Hi", testActor)
}
}
it("ok actor") {
val ref = TestActorRef(new Actor {
def receive = {
case "Hi" => sender ! "Hello"
}
})
ref.tell("Hi", testActor)
expectMsg("Hello")
}
}
"problemExample" passes, but then downstream "ok actor" fails for some reason I don't really understand... with this exception:
cannot reserve actor name '$$b': already terminated
java.lang.IllegalStateException: cannot reserve actor name '$$b': already terminated
at akka.actor.dungeon.ChildrenContainer$TerminatedChildrenContainer$.reserve(ChildrenContainer.scala:86)
at akka.actor.dungeon.Children$class.reserveChild(Children.scala:78)
at akka.actor.ActorCell.reserveChild(ActorCell.scala:306)
at akka.testkit.TestActorRef.<init>(TestActorRef.scala:29)
So, I can see ways of catching this sort of thing by examining the logger output in afterEach handlers. Definitely doable, although a little complicated in cases where I actually expect an exception and that's what I'm trying to test. But is there any more direct way of handling this and making the test fail?
Addendum: I have looked at the TestEventListener and suspect there's maybe something there that would help, but I can't see it. The only documentation I could find was about using it to check for expected exceptions, not unexpected ones.
Thinking in Actors there is also another solution: failures travel to the supervisor, so that is the perfect place to catch them and feed them into the test procedure:
val failures = TestProbe()
val props = ... // description for the actor under test
val failureParent = system.actorOf(Props(new Actor {
val child = context.actorOf(props, "child")
override val supervisorStrategy = OneForOneStrategy() {
case f => failures.ref ! f; Stop // or whichever directive is appropriate
}
def receive = {
case msg => child forward msg
}
}))
You can send to the actor under test by sending to failureParent and all failures—expected or not—go to the failures probe for inspection.
Other than examining the logs, I can think of two ways to fail tests when an actor crashes:
Ensure that no Terminated message is received
Check the TestActorRef.isTerminated property
The latter option is deprecated, so I'll ignore it.
Watching Other Actors from Probes describes how to setup a TestProbe. In this case it might look something like:
val probe = TestProbe()
probe watch ref
// Actual test goes here ...
probe.expectNoMessage()
If the actor dies due to an exception it will generate the Terminated message. If that happens during the test and you expect something else, the test will fail. If it happens after your last message expectation, then the expectNoMessage() should fail when Terminated is received.
Okay, I've had a little time to play with this. I've got a nice solution that uses an event listener and filter to catch errors. (Checking isTerminated or using TestProbes is probably good in more focused cases but seems awkward when trying to make something to mix into any old test.)
import akka.actor.{Props, Actor, ActorSystem}
import akka.event.Logging.Error
import akka.testkit._
import com.typesafe.config.Config
import org.scalatest._
import org.scalatest.matchers.ShouldMatchers
import org.scalatest.mock.EasyMockSugar
import scala.collection.mutable
trait AkkaErrorChecking extends ShouldMatchers {
val system:ActorSystem
val errors:mutable.MutableList[Error] = new mutable.MutableList[Error]
val errorCaptureFilter = EventFilter.custom {
case e: Error =>
errors += e
false // don't actually filter out this event - it's nice to see the full output in console.
}
lazy val testListener = system.actorOf(Props(new akka.testkit.TestEventListener {
addFilter(errorCaptureFilter)
}))
def withErrorChecking[T](block: => T) = {
try {
system.eventStream.subscribe(testListener, classOf[Error])
filterEvents(errorCaptureFilter)(block)(system)
withClue(errors.mkString("Akka error(s):\n", "\n", ""))(errors should be('empty))
} finally {
system.eventStream.unsubscribe(testListener)
errors.clear()
}
}
}
You can just use withErrorChecking inline at specific spots, or mix it into a Suite and use withFixture to do it globally across all tests, like this:
trait AkkaErrorCheckingSuite extends AkkaErrorChecking with FunSpec {
override protected def withFixture(test: NoArgTest) {
withErrorChecking(test())
}
}
If you use this in my original example, then you will get the first test "calls foo only when it receives a message" to fail, which is nice because that's where the real failure is. But the downstream test will still fail as well due to the system blowing up. To fix that, I went a step further and used a fixture.Suite to instance a separate TestKit for each test. That solves lots of other potential test isolation issues when you have noisy actors. It requires a little more ceremony declaring each test but I think it's well worth it. Using this trait with my original example I get the first test failing and the second one passing which is just what I want!
trait IsolatedTestKit extends ShouldMatchers { this: fixture.Suite =>
type FixtureParam = TestKit
// override this if you want to pass a Config to the actor system instead of using default reference configuration
val actorSystemConfig: Option[Config] = None
private val systemNameRegex = "[^a-zA-Z0-9]".r
override protected def withFixture(test: OneArgTest) {
val fixtureSystem = actorSystemConfig.map(config => ActorSystem(systemNameRegex.replaceAllIn(test.name, "-"), config))
.getOrElse (ActorSystem (systemNameRegex.replaceAllIn(test.name, "-")))
try {
val errorCheck = new AkkaErrorChecking {
val system = fixtureSystem
}
errorCheck.withErrorChecking {
test(new TestKit(fixtureSystem))
}
}
finally {
fixtureSystem.shutdown()
}
}
}

Scala remote actors on same machine

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

Scala println not working with App trait

When I use the scala App trait, I can't get println to work.
This simple example prints as expected,
object HelloWorld {
def main(args: Array[String]) {
println("Hello, world!")
}
}
But once I introduce the trait it does not,
object HelloWorld extends App {
println("Hello, world!")
}
I get no errors but nothing prints to the console.
Did you compile it first (running scalac HelloWorld.scala)? See this comment: http://www.scala-lang.org/node/9483#comment-40627
Edited to add more explanation:
The first version actually was compiled. Scala files without an explicit main method are run uncompiled as scripts. That means that for your second version, the commands in the file are run sequentially, as though they had been entered into the interpreter--so, the object HelloWorld is created, but no method is called on it. There's more information about Scala as a scripting language here (scroll to Step 5): http://www.artima.com/scalazine/articles/steps.html
Add a line
object HelloWorld extends App {
/* code */
}
HelloWorld.main(args)
at the end of your file.
The Class defines the method but it need to be called too.
According to
http://www.scala-lang.org/api/current/scala/App.html
you want to do
object Main extends App {
Console.println("Hello World: " + (args mkString ", "))
}

How can I add scala actors to an existing program without interfering with the normal termination behavior?

This program, after executing main(), does not exit.
object Main
{
def main(args: Array[String]) {
... // existing code
f()
... // existing code
}
def f() {
import scala.actors.Actor._
val a = actor {
loop {
react {
case msg: String => System.out.println(msg)
}
}
}
a ! "hello world"
}
}
Because of this unexpected side-effect, using actors can be viewed as intrusive.
Assuming the actors must continue to run until program termination, how would you do to preserve original behavior in all cases of termination?
In 2.8 there's a DaemonActor class that allows this. In 2.7.x I you could hack in a custom scheduler that doesn't prevent shutdown even if there are still live actors, or if you want an easy way you could call System.exit() at the end of main.
If you think of an actor as kind of a light-weight thread, much of the time you want a live actor to prevent program termination. Otherwise if you have a program that does all of its work in actors, you'd need to have something on the main thread just to keep it alive until all the actors finish.
After the main thread in the above example completed, the program still had a non-daemon thread running the actor. It is usually a bad idea to brutally terminate running threads using Thread.destroy() or System.exit() for results may be very bad for your program including, but not limited to, data corruption and deadlocks. That is why Thread.destroy() and alike methods were deprecated in Java for the first place. The right way would be to explicitly implement termination logic in your threads. In case of Scala actors that boils down to sending a Stop message to all running actors and make them quit when they get it. With this approach your eample would look like this:
object Main
{
case object Stop
def main(args: Array[String]) {
... // existing code
val a = f()
a ! "hello world"
... // existing code
a ! Stop
}
def f() = {
import scala.actors.Actor._
actor {
loop {
react {
case msg: String => System.out.println(msg)
case Stop => exit()
}
}
}
}
}

Method call inside Actor freezes in Scala

I have the following code. If I comment the call to "foo()" inside the actor's body, the code works fine. But if "foo()" is activated... my code freezes!
Anyone kwnows why?
import scala.actors.Actor._
object Main extends Application{
def foo() = {
println("I'm on foo")
}
def testActor() = {
val target = self
for(i <- 1 to 100){
actor{
foo()
target ! i
}
}
var total = 0
receive{
case x:Int => total += x
}
total
}
println("Result: " + testActor())
}
"testActor" is called while the "Main" class is initializing. The actor code is executing in a different thread(not the main thread) and it's blocked and can not send any message because it's trying to access a method in a class (Main in this case) that is being initialized in the main thread. "receive" hangs because it can not receive any message.
Do not use "extends Application". Use "def main(args: Array[String])" and save yourself a lot of trouble.
See http://scala-blogs.org/2008/07/application-trait-considered-harmful.html
The Application trait and its use is at fault here. When you have code running within the body of a Application rather than within a main method, that code is actually running as part of the constructor. So at the point where you call the testActor() method, the object hasn't actually finished initialising.
To fix it, move the println line into a main method:
def main (args: Array[String]) {
println("Result: " + testActor())
}
Because this problem happens so easily, the Application trait is considered to be bad news.