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
Related
I want to do something like this:
For every item in the collection, ask an actor and block while waiting for the response for some timeout interval, if the time out exception is thrown, I want to move on to the next item.
Here's the code pattern:
implicit val timeout: akka.util.Timeout = 3 seconds
collection.foreach { item =>
val future = (actor ? Request(msg = item)).mapTo[Response]
future.onComplete {
case Failure(ex) => // log ex
case Success(resp) => // use resp
}
Await.result(future, 3 seconds)
}
The actor is itself calling other actors which might take longer than my 3 second time out.
This doesn't work as expected: after the first item times out, the whole thing crashes and stops. There are some dead letter notifications, I suppose that's because when the actors that my actor is calling finish, the original sender is invalid (it took more than 3 seconds). So my question is how do I tell it to just forget the time out item and continue with the rest as if nothing happened?
#stefanobaghino is right. See here, as written in documentation if a future contains an exception then Await.result throws is so that it can be handled properly.
Here you are matching Failure case of future but you are not recovering from it. A better approach would be like following -
collection.foreach { item =>
val future = (actor ? Request(msg = item)).mapTo[Response]
future.recover {
case ex: Exception =>
// log ex
Response(ex.message) // some other object of type Response
}
val response = Await.result(future, 3 seconds)
// use response here
}
After reading answer by #Dimitri I tried logging timestamps in milliseconds to see where it was causing lag in whole process and i found rather strange behavior. I observed that whenever there were dead-letters there was huge lag in even starting processing of next message to actor. Not sure why this is happening. Below is the code i tried to check it -
package com.lightbend.akka.sample
import akka.actor.{ Actor, ActorLogging, ActorRef, ActorSystem, Props }
import akka.pattern.{ ask, pipe, AskTimeoutException }
import scala.concurrent.Await
import scala.concurrent.duration._
import scala.io.StdIn
import scala.util.{ Try, Success, Failure }
import scala.concurrent.ExecutionContext.Implicits.global
import java.util.concurrent.TimeoutException
object AkkaQuickStart {
class NumberActor extends Actor {
override def receive: Receive = {
case (num: Int, startAt: Long) =>
println("B " + num.toString + " : " + System.currentTimeMillis().toString + " : " + (System.currentTimeMillis() - startAt).toString)
Thread.sleep(500 * num)
sender() ! "OK"
}
}
def main(args: Array[String]): Unit = {
implicit val timeout: akka.util.Timeout = 1 seconds
val numActor = ActorSystem("system").actorOf(Props(new NumberActor()))
val range = (1 to 5) ++ (4 to 1 by -1)
println(range)
def lag(implicit startAt: Long): String = (System.currentTimeMillis() - startAt).toString
range.map { r =>
implicit val startAt = System.currentTimeMillis()
println("A " + r.toString + " : " + System.currentTimeMillis().toString + " : " + lag)
val future = (numActor ? (r, startAt))
.recover {
case ex: AskTimeoutException =>
println("E " + r.toString + " : " + System.currentTimeMillis().toString + " : " + lag)
"Ask timeout"
}
.mapTo[String]
future.onComplete{
case Success(reply) =>
println("C " + r.toString + " : " + System.currentTimeMillis().toString + " : " + lag + " : success " + reply)
case Failure(reply) =>
println("C " + r.toString + " : " + System.currentTimeMillis().toString + " : " + lag + " : failure")
}
Try(Await.result(future, 1 seconds)) match {
case Success(reply) =>
println("D " + r.toString + " : " + System.currentTimeMillis().toString + " : " + lag + " : " + reply)
case Failure(ex) =>
println("D " + r.toString + " : " + System.currentTimeMillis().toString + " : " + lag + " : Await timeout ")
}
}
}
}
I tried different combinations of Ask timeout and Await timeout and found following lags in starting processing of actor message sent at the end of iteration -
Ask timeout = 1 Await Timeout = 1 => 3000 - 4500 ms causes dead-letters
Ask timeout = 1 Await Timeout = 3 => 3000 - 4500 ms causes dead-letters
Ask timeout = 3 Await Timeout = 1 => 3000 - 4500 ms causes dead-letters
Ask timeout = 3 Await timeout = 3 => 0 - 500 ms does not cause dead-letters
I am not sure but a guess is that dispatcher takes time in handling dead-letters and thus can not start processing messages of our Actor. May be some more experienced can explain it.
#stefanobaghino #Tarun Thanks for your help, I think I got it now.
So the thing is there are 2 timeouts that can cause an exception:
The Ask (?) timeout throws akka.pattern.AskTimeoutException if we have to wait longer than the actor takes to respond.
The Await.result throws java.util.concurrent.TimeoutException if we don't wait long enough for the future to finish.
Both of these can cause the whole thing to crash. For the first one, as you mentioned, we can add recover to return some default value. For the second one, we also should catch and handle the exception.
You can see different behaviours when changing the two timeouts and removing the recover/Try in the following example:
object Example {
class NumberActor extends Actor {
override def receive: Receive = {
case num: Int =>
Thread.sleep(250 * num)
sender() ! "OK"
}
}
def main(): Unit = {
implicit val timeout: akka.util.Timeout = 1 seconds
val numActor = ActorSystem("system").actorOf(Props(new NumberActor()))
val range = (1 to 5) ++ (4 to 1 by -1)
println(range)
range.map { r =>
val future = (numActor ? r)
.recover { case ex: TimeoutException => "FAIL" }
.mapTo[String]
Try(Await.result(future, 1 seconds)) match {
case Success(reply) => println(reply)
case Failure(ex) => println(ex)
}
}
}
}
This is a simple scala code for checking prime number.
When I compile at command prompt, I get the following warning. I thought I would care less for warning. But it didn't create the .class files.
Can someone share what this warning means?
warning: This catches all Throwables. If this is really intended, use case _ : Throwable to clear this warning.
object PrimeNumber extends App {
println("11 is prime number : " + checkPrimeNumber(11))
println("111 is prime number : " + checkPrimeNumber(111))
//Method for checking prime numbers between 1 and 100
def checkPrimeNumber(num: Int) = {
try {
if (num < 1 || num > 100)
throw new IllegalArgumentException("Number should be between 1 and 100")
else
isPrimeNumber(num)
} catch {
case e: IllegalArgumentException => e.printStackTrace()
case _ => println("Exception has occurred!")
}
}
//Non Functional Method for finding prime number
def isPrimeNumber(number: Int): Boolean = {
var i = 2
while (i <= number / 2) {
if (number % i == 0) {
return false
}
i += 1
}
true
}
}
It is dangerous to catch Throwable in Java, and even more in Scala.
Instead, use this:
catch { case scala.util.control.NonFatal(e) => // do something }
See http://www.tzavellas.com/techblog/2010/09/20/catching-throwable-in-scala/
This question already has an answer here:
How come the following code prints Success(4) if i'm throwing an exception inside?
(1 answer)
Closed 7 years ago.
println(
Try(1)
.map(doOne)
.map(doTwo)
.recover {
// this catches only errors from doTwo
case e: Throwable => println("recovering from: " + e.getMessage)
}
)
def doOne(i: Int): Int = i + 1; throw new RuntimeException("failed in one")
def doTwo(i: Int): Int = i + 2
How can a single recover catch any errors from preceeding maps?
It would catch both error. Isn't your problem just that you forgot bracket in doOne?
That should be :
def doOne(i: Int): Int = { i + 1; throw new RuntimeException("failed in one")}
Otherwise, it just means
def doOne(i: Int) = i + 1
throw new RuntinmeException ...
The exception is thrown at the start of your program, completely outside Try.
Scala 2.10.2. Running
import util.continuations._
import concurrent.ops._
object Main {
def main(args: Array[String]) {
reset {
try {
shift { cont: (Unit => Unit) => {
spawn {
throw new Exception("blah")
cont()
}
}}
println("after shift")
} catch {
case e: Exception => println(e)
}
println("reset end")
}
}
}
Gives
Cont.scala:16: error: type mismatch;
found : Unit
required: Unit #scala.util.continuations.cpsParam[Unit,Unit]
case e: Exception => println(e)
^
one error found
If I remove the try/catch block everything's fine. I'm still trying to figure out how continuations work in Scala, but this one totally eludes me.
Just stating the obvious - It is a Scala type inference meets cps-annotation problem. The catch block do not contain any cps annotated expression. In this case the catch-block is expected to be of the same type as the try-block:
Unit #cps[Unit] // same as Unit #cpsParam[Unit,Unit]
To my experience, the type-inference and the CPS-transformation in Scala does not always work as expected and things that work in one version of Scala do not work in another version.
There exists workarounds such as the try_protector mentioned in Scala Continuations - Why can't my shifted call be inside a try-catch block?
Not sure if it helps in your case (i.e. Scala version 2.10.2).
Do you intend the try/catch statement to catch Exception("blah")?
Even if it compiled, spawn which is deprecated would happen on another thread before the flow gets to running the continuation.
Without the try/catch you have something like this:
println("in main " + Thread.currentThread())
reset {
shift { cont: (Unit => Unit) =>
{
spawn {
println("in spawned " + Thread.currentThread())
cont()
}
}
}
println("after shift " + Thread.currentThread())
println("reset end")
}
}
The cont function is the reified portion of code which corresponds to this function:
val cont = () => {
println("after shift " + Thread.currentThread())
println("reset end")
}
So when you do spawn { cont() }, you just run the two println in a new separate thread. Running the program, I get:
in main Thread[main,5,main]
in spawned Thread[Thread-1,5,main]
after shift Thread[Thread-1,5,main]
reset end
That shows that the continuation ran on a separate thread. Now if you insert a throw new Exception() before cont(), then all you get is an exception thrown on the spawned thread (where apparently the exception would be swallowed).
Would running the continuation inside a try/catch and having an exception thrown after the shift be more what you are trying to do?
reset {
shift { cont: (Unit => Unit) =>
spawn {
println("in spawned " + Thread.currentThread())
try { cont() }
catch { case e: Exception => println(e) }
}
}
println("after shift " + Thread.currentThread())
throw new Exception("blah")
println("reset end")
}
}
This prints:
in main Thread[main,5,main]
in spawned Thread[Thread-1,5,main]
after shift Thread[Thread-1,5,main]
java.lang.Exception: blah
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.