Say I have a worker actor that receives a message, does a bit of processing and returns a result. And I have a sequence of messages that need to be converted into a sequence of results:
object Test {
case class Message(str: String)
case class Result(str: String)
class Worker extends Actor {
def receive = {
case Message(data) =>
println("Sleeping: " + data)
Thread.sleep(10000)
val result = Result(data + " - result")
println("Sending result: " + result)
sender ! result
}
}
def test(messages: Seq[Message]): Future[Seq[Result]] = {
val worker = ActorSystem().actorOf(Props(new Worker))
val results = messages.map { m =>
implicit val timeout = Timeout(20 seconds)
println("Sending: " + m)
val result = worker ? m
result.asInstanceOf[Future[Result]]
}
Future.sequence(results)
}
def main(args: Array[String]): Unit = {
val messages: Seq[Message] = args.map(Message(_))
test(messages).foreach { r =>
println("Result: " + r)
}
}
}
If I run the above with just "message-1" as an argument it runs fine giving the the output is below:
Sending: Message(message-1)
Sleeping: message-1
Sending result: Result(message-1 - result)
Result: ArraySeq(Result(message-1 - result))
However say I do it with: "message-1" "message-2" "message-3" then the last message ends up being sent to deadLetters:
Sending: Message(message-1) Sending: Message(message-2) Sleeping:
message-1 Sending: Message(message-3)
Sending result: Result(message-1 - result)
Sleeping: message-2
Sending result: Result(message-2 - result)
Sleeping: message-3
Sending result: Result(message-3 - result)
[INFO] [07/15/2016 09:07:49.832]
[default-akka.actor.default-dispatcher-2] [akka://default/deadLetters]
Message [util.Tester$Result] from
Actor[akka://default/user/$a#1776546850] to
Actor[akka://default/deadLetters] was not delivered. [1] dead letters
encountered. This logging can be turned off or adjusted with
configuration settings 'akka.log-dead-letters' and
'akka.log-dead-letters-during-shutdown'.
I am guessing this is because my calling thread has gone out of scope by the time the last message is sent. How can correctly collect all results into a sequence?
Note that changing my test method to below gives the same results:
def test(messages: Seq[Message]): Future[Seq[Result]] = {
val worker = ActorSystem().actorOf(Props(new Worker))
Future.traverse(messages) { m =>
implicit val timeout = Timeout(20 seconds)
println("Sending: " + m)
val result = worker ? m
result.asInstanceOf[Future[Result]]
}
}
The dumb answer is:
Future.traverse(messages)(m => actor ? m).map(_.asInstanceOf[Result])
But it might be better to send data all at once:
class Worker extends Actor {
def receive = {
case Message(data) =>
// Convert data into result
...
sender ! result
case seq: Seq[Message] =>
...
sender ! results
}
}
Seems to be because my timeout was set too low. Should have been large enough to cover all the work - for example 40 seconds.
I would like to remove the timeout definition from the code below so it doesn't time out within the defined period. How can i achieve that?
val futureString: Future[String] = myTestActor.ask(Message).mapTo[String]
val timeoutFuture: Future[String] = play.api.libs.concurrent.Promise.timeout(throw new TimeoutException(), 5 seconds)
Async {
Future.firstCompletedOf(Seq(futureString, timeoutFuture)) map {
case result: String => println("got message " + result)
} recover {
case _: TimeoutException => "Timed out?"
}
}
The cases in the act method of the main actor are never matched in this code, so my wrapUp method is never called.
import java.net.Socket
import scala.actors._
import Actor._
import scala.collection.mutable.ArrayBuffer
object LowPortScanner {
var lastPort = 0
var openPorts = ArrayBuffer[Int]()
var longestRunTime = 00.00
var results = List[Tuple3[Int, Range, Long]]()
val host = "localhost"
val numProcs = 1 to Runtime.getRuntime().availableProcessors()
val portsPerProc = 1024 / numProcs.size
val caller = self
val procPortRanges = numProcs.foldLeft(List[Tuple2[Int, Range]]()) { (portRanges, proc) =>
val tuple2 = (proc.toInt, (lastPort + 1) to (lastPort + portsPerProc))
lastPort += portsPerProc
tuple2 :: portRanges
}
def main(args: Array[String]): Unit = {
//spawn an actor for each processor that scans a given port range
procPortRanges.foreach { proc =>
actor {
caller ! scan(proc._1, proc._2)
} //end inner actors
} //end numProcs.foreach
//catch results from the processor actors above
def act {
loop {
reactWithin(100) {
//update the list of results returned from scan
case scanResult: Tuple3[Int, Range, Long] =>
println("Processor " + scanResult._1 + " completed scan of ports " + scanResult._2.first + " through " + scanResult._2.last)
results = results ::: List(scanResult)
//check if results have been returned for each actor
case TIMEOUT =>
println("Main actor timed out")
if (results.size == numProcs.size) wrapUp
case _ =>
println("got back something weird from one of the port scan actors!")
wrapUp
}
}
}
//Attempt to open a socket on each port in the given range
//returns a Tuple3[procID: Int, ports: Range, time: Long
def scan(proc: Int, ports: Range) = {
val startTime = System.nanoTime()
ports.foreach { n =>
try {
//println("Processor " + proc + " is checking port " + n)
print(".")
val socket = new Socket(host, n)
//println("Found open port: " + n)
openPorts += n
socket.close
} catch {
case e: Exception =>
//println("While scanning port " + n + " caught Exception: " + e)
}
}
(proc, ports, startTime - System.nanoTime())
}
//output results and kill the main actor
def wrapUp {
println("These are the open ports in the range 1-1024:")
openPorts.foreach { port => println(port) }
results.foreach { result => if (result._3 > longestRunTime) { longestRunTime = result._3 } }
println("Time to scan ports 1 through 1024 is: %3.3f".format(longestRunTime / 1000))
caller ! exit
}
}
}
The code that spawns off the actors for each processor works fine, the scan method is invoked correctly for each range of ports, and I have confirmed that exactly 1024 ports are scanned.
My expectation is that the line :
caller ! scan(proc._1, proc._2)
should send a message containing (Int, Range, Long) back to the main actor. The main actor's act method should then catch that message and execute:
case scanResult: Tuple3[Int, Range, Long] =>
println("Processor " + scanResult._1 + " completed scan of ports " + scanResult._2.first + " through " + scanResult._2.last)
results = results ::: List(scanResult)
This is not happening, however. In fact, as far as I can tell, none of my messages are coming back to the main actor. I'm not clear on what I'm missing or doing wrong.
The problem as you note is that the message being sent are not being received. This is because the actor created with actor {caller ! scan(proc._1, proc._2)} does not have an act definition associated with it. The def act{...} method has nothing to do with the actor created since it is a method on LowPortScanner and not an actor.
Maintaining the spirit of your code you can define the body to be executed by the actor within the actor{...} and assign it to a value and send it messages.
//spawn an actor for each processor that scans a given port range
procPortRanges.foreach { proc =>
val myactor = actor {
//catch results from the processor actors above
loop {
reactWithin(100) {
//update the list of results returned from scan
case scanResult: Tuple3[Int, Range, Long] =>
println("Processor " + scanResult._1 + " completed scan of ports " + scanResult._2.first + " through " + scanResult._2.last)
results = results ::: List(scanResult)
//check if results have been returned for each actor
case TIMEOUT =>
println("Main actor timed out")
if (results.size == numProcs.size) wrapUp
case _ =>
println("got back something weird from one of the port scan actors!")
wrapUp
}
}
//catch results from the processor actors above
} //end inner actors
myactor ! scan(proc._1, proc._2)
} //end numProcs.foreach
Another way to do it is to extend the Actor trait. This way the def act{...} will handle messages received by the LowPortScanner actor. I also did some minor refactoring including using this instead of self. The Actor also had to be started with this.start().
import java.net.Socket
import scala.actors._
import Actor._
import scala.collection.mutable.ArrayBuffer
object LowPortScanner extends Actor {
var lastPort = 0
var openPorts = ArrayBuffer[Int]()
var longestRunTime = 00.00
var results = List[Tuple3[Int, Range, Long]]()
val host = "localhost"
val numProcs = 1 to Runtime.getRuntime().availableProcessors()
val portsPerProc = 1024 / numProcs.size
val procPortRanges = numProcs.foldLeft(List[Tuple2[Int, Range]]()) { (portRanges, proc) =>
val tuple2 = (proc.toInt, (lastPort + 1) to (lastPort + portsPerProc))
lastPort += portsPerProc
tuple2 :: portRanges
}
//catch results from the processor actors above
def act {
loop {
reactWithin(100) {
//update the list of results returned from scan
case scanResult: Tuple3[Int, Range, Long] =>
println("Processor " + scanResult._1 + " completed scan of ports " + scanResult._2.first + " through " + scanResult._2.last)
results = results ::: List(scanResult)
//check if results have been returned for each actor
case TIMEOUT =>
println("Main actor timed out")
if (results.size == numProcs.size) wrapUp
case _ =>
println("got back something weird from one of the port scan actors!")
wrapUp
}
}
}
//Attempt to open a socket on each port in the given range
//returns a Tuple3[procID: Int, ports: Range, time: Long
def scan(proc: Int, ports: Range) = {
val startTime = System.nanoTime()
ports.foreach { n =>
try {
//println("Processor " + proc + " is checking port " + n)
print(".")
val socket = new Socket(host, n)
//println("Found open port: " + n)
openPorts += n
socket.close
} catch {
case e: Exception =>
//println("While scanning port " + n + " caught Exception: " + e)
}
}
(proc, ports, startTime - System.nanoTime())
}
//output results and kill the main actor
def wrapUp {
println("These are the open ports in the range 1-1024:")
openPorts.foreach { port => println(port) }
results.foreach { result => if (result._3 > longestRunTime) { longestRunTime = result._3 } }
println("Time to scan ports 1 through 1024 is: %3.3f".format(longestRunTime / 1000))
this ! exit
}
def main(args: Array[String]): Unit = {
//spawn an actor for each processor that scans a given port range
this.start()
procPortRanges.foreach { proc =>
actor {
this ! scan(proc._1, proc._2)
} //end inner actors
} //end numProcs.foreach
}
}
Here are the results from a run:
scala> LowPortScanner.main(Array[String]())
scala> ...Processor 6 completed scan of ports 641 through 768
...Processor 5 completed scan of ports 513 through 640
...Processor 4 completed scan of ports 385 through 512
...Processor 3 completed scan of ports 257 through 384
...Processor 1 completed scan of ports 1 through 128
...Processor 7 completed scan of ports 769 through 896
...Processor 2 completed scan of ports 129 through 256
...Processor 8 completed scan of ports 897 through 1024
Main actor timed out
These are the open ports in the range 1-1024:
139
22
445
591
631
111
Time to scan ports 1 through 1024 is: 0.000
scala> LowPortScanner.results
res2: List[(Int, Range, Long)] = List((6,Range(641, 642, 643,...
Starting from this answer:
Scala continuation and exception handling
I would like to know if there is a way to re-execute the ENTIRE try block (or ctry block in the example code) after the exception is handled.
What I mean is if the resume() operation could move the execution to the first statement of the try block instead of simply resuming the execution from the statement that raised the exception.
Thanks a lot!
Here's a silly example that I think will steer you toward an answer:
object Retry
object SO_7331489 extends App {
import scala.util.continuations._
var dividend: String = "ten"
var divisor: Int = 0
val quotient = reset {
shift { k: (Unit => Any) =>
def retry: Any =
k() match {
case Retry => retry
case x => x
}
retry
}
try {
dividend.toInt / divisor
} catch {
case e: java.lang.NumberFormatException =>
println("caught " + e.getClass.getName + "(" + e.getMessage + ")")
dividend = "10"
println("retrying with dividend = \"10\"")
Retry
case e: java.lang.ArithmeticException =>
println("caught " + e.getClass.getName + "(" + e.getMessage + ")")
divisor = 2
println("retrying with divisor = 2")
Retry
case t: Throwable =>
println("caught " + t.getClass.getName + "(" + t.getMessage + ")")
// Nothing left to retry, so don't return Retry
}
}
println("quotient: " + quotient)
}
The idea is to trigger the shift block before your try/catch block. Within the catch block, if you want to retry the whole thing, simply return the Retry object.
It might be nice to pull the entire shift block out into a simple function (e.g. retry), but I left it inline for clarity.
This code produces the following output:
[info] Running SO_7331489
caught java.lang.NumberFormatException(For input string: "ten")
retrying with dividend = "10"
caught java.lang.ArithmeticException(/ by zero)
retrying with divisor = 2
quotient: 5
I want to rewrite in scala the example from Sun's tutorial about concurrency in java. The original code is here: http://java.sun.com/docs/books/tutorial/essential/concurrency/deadlock.html
This code is incorrect. It freezes at where the comment indicates. Could anyone correct this? Thanks in advance.
import scala.actors.Actor
class Person(val name: String) extends Actor {
def bow(other: Person) {
other ! Bow(this)
}
private def bowBack(backTo: Person) {
println(this.name + " is bowing back to " + backTo.name)
backTo ! Bowed(this)
}
def act() {
while (true) {
receive {
case Bow(p) =>
println(this.name + " is bowing to " + p.name)
p ! BowBack(this)
println(" wating for bowing back...")
var received = false
while (true && received == false) {
receive { //blocked here
case Bowed(other) if p == other =>
println(" ... " + this.name + " has bowed to " + other.name)
received == true
}
}
println(this.name + " has bowed to " + p.name)
case BowBack(p) =>
println(this.name + " is bowing back to " + p.name)
p ! Bowed(this)
case "EXIT" => return
case x => println(x)
}
}
}
}
abstract case class Action()
case class Bow(person: Person) extends Action
case class BowBack(person: Person) extends Action
case class Bowed(person: Person) extends Action
object BowTest extends Application {
val a = new Person("Alphone")
val g = new Person("Gaston")
a.start()
g.start()
a ! Bow(g)
//g.bow(a)
a ! "EXIT"
g ! "EXIT"
}
The first mistake is that you wrote result == true. This should be changed to result = true
You should delete the true value from the while condition. It has no influence.
In the BowTest object you should add after the g.bow(a) instruction Thread.sleep(1000) to give actors enough time to respond to the messages.
In this way your code should work. But still it has a deadlock. If you will change g.bow(a) in a.bow(g) the execution will freeze. This is caused by the receive block. Each actor is waiting for the Bowed message, but they cannot respond to the BowBack message.
When you are responding to a message, you should use receive block only if you are sure that the actor will get the specified messages. But usually this is not a good practice in designing actors. They should not block. The main purpose of an actor is to respond as fast as possible to a message. If you have to do a big task you should use futures, but in this case is not required.
A solution will be to retain the persons which are bowed in a list. When the actor have to bow a person it adds it in the list. When the actor is bowed by a person which is in the list, it removes that person from the list.
while (true) {
react {
case Bow(p) =>
println(this.name + " is bowing to " + p.name)
addPersonToBowList(p)
p ! BowBack(this)
case Bowed(other) if isPersonInBowList(other) =>
println(" ... " + this.name + " has bowed to " + other.name)
removePersonFromBowList(other)
case BowBack(p) =>
println(this.name + " is bowing back to " + p.name)
p ! Bowed(this)
case "EXIT" => exit()
case x => println(x)
}
}
Not deadlock, just a plain ol' bug, I think. Two lines under your comment:
received == true
This should be = instead of ==. I've not looked in depth (this sprung out at me) but it looks like this would fix your issue.