Why does Future's recover not catch exceptions? - scala

I'm using Scala, Play Framework 2.1.x, and reactivemongo driver.
I have an api call :
def getStuff(userId: String) = Action(implicit request => {
Async {
UserDao().getStuffOf(userId = userId).toList() map {
stuffLst => Ok(stuffLst)
}
}
})
It works fine 99% of the time but it may fail sometimes (doesn't matter why, that's not the issue).
I wanted to recover in a case of an error so i added:
recover { case _ => BadRequest("")}
But this does not recover me from errors.
I tried the same concept on the scala console and it worked:
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
var f = future { throw new Exception("") } map {_ => 2} recover { case _ => 1}
Await.result(f, 1 nanos)
This returns 1 as expected.
I currently wrapped the Async with:
try{
Async {...}
} catch {
case _ => BadRequest("")
}
And this catches the errors.
I went over some Scala's Future docs on the net and I'm baffled why recover did not work for me.
Does anyone know why? What do I miss to sort it out?

Why it fails actually matters 100%. If we spread the code over a number of lines of code, you'll understand why:
def getStuff(userId: String) = Action(implicit request => {
Async {
val future = UserDao().getStuffOf(userId = userId).toList()
val mappedFuture = future.map {
stuffLst => Ok(stuffLst)
}
mappedFuture.recover { case _ => BadRequest("")}
}
})
So, UserDao().getStuffOf(userId = userId).toList() returns you a future. A future represents something that may not have happened yet. If that thing throws an exception, you can handle that exception in recover. However, in your case, the error is happening before the future is even being created, the UserDao().getStuffOf(userId = userId).toList() call is throwing an exception, not returning a future. So the call to recover the future will never be executed. It's equivalent to doing this in the Scala repl:
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
var f = { throw new Exception(""); future { "foo" } map {_ => 2} recover { case _ => 1} }
Await.result(f, 1 nanos) }
Obviously that doesn't work, since you never created the future in the first place beacuse the exception was thrown before the code to create the future happened.
So the solution is to either wrap your call to UserDao().getStuffOf(userId = userId).toList() in a try catch block, or find out why it's failing in whatever method you're calling, and catch the exception there, and return a failed future.

If you have a later version of Play eg 2.2.x, you can do this:
def urlTest() = Action.async {
val holder: WSRequestHolder = WS.url("www.idontexist.io")
holder.get.map {
response =>
println("Yay, I worked")
Ok
}.recover {
case _ =>
Log.error("Oops, not gonna happen")
InternalServerError("Failure")
}
}

Related

How to avoid try with Future fromTry

I need to write a future that flushes a stream and closes it. Here is what I tried:
def close(ous: OutputStream) = Future.fromTry(Try {
try {
ous.flush()
} finally {
ous.close()
}
})
Looks ugly. try{}finally{} inside the Try. But I need finally block in order to avoid resource leak. Is there a way to rewrite the code in not so ugly way?
Future already captures exceptions returning a Future.failed, there's no need to do fromTry and block, so you can do:
Future { out.flush() }.andThen( _=> out.close )
( Future { out.flush() } will asynchronously flush the stream and andThen will get called wether it finishes or fails.
This could be an option i think.
def close(ous: OutputStream) = Future.fromTry(Try(ous.flush())) andThen {
case Success(_) => println("do something here")
case Failure(_) => ous.close()
}
It's not clear to me whether this is actually cleaner:
def close(ous: OutputStream) = Future.fromTry(
val flushed = Try { ous.flush() }
val closed = Try { ous.close() }
if (closed.isFailure) closed else flushed // bubble up the correct error
)
Note: This is nearly an equivalent of this answer but not quite. Mainly since the .close can fail, and this must be encapsulated in the Try.
since you are already using Try use pattern match on result to Try{ stream.flush } and apply Try{ stream.close() }
example,
import java.io.{ByteArrayOutputStream, OutputStream}
import java.util.Date
import java.io.ObjectOutputStream
import scala.concurrent.Future
import scala.util.Try
import scala.util.{Failure, Success}
import scala.concurrent.ExecutionContext.Implicits.global
def doSomeOperation: OutputStream => Future[String] = (outputStream: OutputStream) =>
withCleanup(outputStream) {
Future {
//1/0
outputStream.toString
}
}
def withCleanup(outputStream: OutputStream)(fn: Future[String]): Future[String] = {
val execution = fn
execution onComplete {
case Success(_) => cleanup(outputStream)
case Failure(_) => cleanup(outputStream)
}
execution
}
def cleanup(outputStream: OutputStream): Try[Unit] = Try {
outputStream.flush()
println("flushed")
} match {
case _ => Try {
outputStream.close()
println("closed")
}
}
Then call the function, which will flush and close your stream as well.
val stream = new ObjectOutputStream(new ByteArrayOutputStream())
stream.writeObject(new Date())
scala> doSomeOperation(stream)
res18: scala.concurrent.Future[String] = Future(<not completed>)
flushed
closed

Scala Future not printing results

I am learning Scala Future with the following code:
object DangerousAndSlowService {
def queryNextNumber: Long = {
50
}
}
val number1F = Future { DangerousAndSlowService.queryNextNumber }
number1F.onComplete({
case Success(value) => {
println(s"Got the callback, meaning = $value")
}
case Failure(exception) => {
exception.printStackTrace
}
})
However, the "50" is never printed.
Already spent several hours but still cannot figure it out.
Thanks.
The main thread exits without letting the future finish its job, therefore the output is non-deterministic: sometimes it does print something, sometimes it doesn't. If you don't mind blocking the main thread, you can use Await:
import scala.concurrent.Future
import scala.util.{Success, Failure}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._
object DangerousAndSlowService {
def queryNextNumber: Long = {
50
}
}
val number1F = Future { DangerousAndSlowService.queryNextNumber }
number1F.onComplete({
case Success(value) => {
println(s"Got the callback, meaning = $value")
}
case Failure(exception) => {
exception.printStackTrace
}
})
Await.result(number1F, 1.second)
While Await is necessary here to produce the output, it's also good to note you should use it with caution. It blocks the current thread, which is typically not what you want when you work with asynchronous computations and futures.

Try Failure is not catching exceptions

In the code below I have two Play for Scala functions, the first one catches an exception (this works fine) and in the second one I'm trying to rewrite it using Try.
I have two problems with Try: (1) when the number is negative the method doesn't fail, (2) I need to wrap all the responses with Future.successful.
How to fix this code?
class Test extends Controller {
def test1 = Action.async { request =>
val future = isPositive(-1)
future.map { result =>
Ok("OK, it's positive")
}
.recover {
case e => Ok(e.getMessage)
}
}
def isPositive(i: Int) = Future {
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
def test2 = Action.async { request =>
isPositiveWithTry(-1) match {
case Success(s) => Future.successful(Ok("OK, it's positive (Try succeded)"))
case Failure(f) => Future.successful(Ok(f.getMessage + " (Try failed)"))
}
}
def isPositiveWithTry(i: Int) : Try[Future[Int]] = Try {
isPositive(i)
}
}
In isPositive method exceptions are already caught by Future
def isPositive(i: Int) = Future {
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
In the below code
def isPositiveWithTry(i: Int) : Try[Future[Int]] = Try {
isPositive(i)
}
isPositive already catches all expections and Try is always a success.
So, when i is negative. Exception raised are handled by future and try gets a success value, resultant Try is a success. So you get successful Try with a failed Future inside.
Understanding using Grenade example
Assume throwing the exception as blowing up a Grenade.
Assume Future and Try as two layers. When grenade is blasted inside the double layer of Try[Future] i.e Try is around Future and grenade is gone off in the Future.
Now Future withstands the blast and becomes a failed value. As Future already took the damage caused by the damage of exception(grenade). Try will be a success but the value inside the Try is a failed future value. That failed future value is nothing but the exception raised.
Try is redundant when you are using Future
You can refactor your code to below one
Get rid of isPositiveWithTry. This method is not needed.
def isPositive(i: Int) = Future {
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
def test2 = Action.async { request =>
isPositive(-1).flatMap { _ =>
Future.successful(Ok("OK, it's positive (Try succeded)"))
}.recoverWith {
case f: Throwable => Future.successful(Ok(f.getMessage + " (Try failed)"))
}
}
Again test2 can also be written as
def test2 = Action.async { request =>
isPositive(-1).map { _ =>
Ok("OK, it's positive (Try succeded)")
}.recover {
case f: Throwable => Ok(f.getMessage + " (Try failed)")
}
}
In case isPositive returns Try
def isPositive(i: Int) = Try {
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
Now test2 will look like
def test2 = Action.async { request =>
isPositive(-1) match {
case Success(s) => Future.successful(Ok("OK, it's positive (Try succeded)"))
case Failure(f) => Future.successful(Ok(f.getMessage + " (Try failed)"))
}
}
Couple points:
1) You need to rewrite your isPositive such that it does not surround itself via a Future. The Future is catching the exception.
def isPositive(i: Int) ={
if (i<0)
throw new Exception ( "Number is negative" )
else
i
}
2) If you have a Try and you want a Future, then you can use the method on the companion object of Future, Future.fromTry. That will take a Try and turn it into the correct state of a Future.

How to handle unhandled exception throw in monix onErrorHandle

I am using monix tasks and i am trying to catch a Throwable and then convert to a custom error. I have removed/changed the code to be simple and relevant. This is the code (question follows after the code snippet):
import io.netty.handler.codec.http.HttpRequest
import monix.reactive.Observable
import io.netty.buffer.ByteBuf
import monix.eval.Task
import com.mypackage.Response
private[this] def handler(
request: HttpRequest,
body: Observable[ByteBuf]
): Task[Response] = {
val localPackage = for {
failfast <- Task.eval(1 / 0)
} yield failfast
// Failure case.
localPackage.onErrorRecoverWith {
case ex: ArithmeticException =>
print(s"LOG HERE^^^^^^^^^^^^^^^")
return Task.now(
Response(HttpResponseStatus.BAD_REQUEST,
None,
None)
)
}.runAsync
// Success case.
localPackage.map { x =>
x match {
case Right(cool) =>
Response(
HttpResponseStatus.OK,
None,
cool
)
case Left(doesntmatter) => ???
}
}
}
I am able to see the print statement but the expected Task.now(Response(... is not being returned. Instead the method that calls the handler method is throwing an error. How do i make it return the Task[Response] ?
The success case works, the failure case does not.
Edit #1 : Fix errors in scala code.
Edit #2 This is how I fixed it.
// Success case.
localPackage.map { x =>
x match {
case Right(cool) =>
Response(
HttpResponseStatus.OK,
None,
cool
)
case Left(doesntmatter) => ???
}
}.onErrorRecoverWith {
case ex: ArithmeticException =>
print(s"LOG HERE^^^^^^^^^^^^^^^")
return Task.now(
Response(HttpResponseStatus.BAD_REQUEST,
None,
None)
)
}
I was thinking in terms of future and forgot the lazy eval nature of task. Also I understood how the CancellableFuture value was being discarded in the failure task.
Several problems with your sample.
For one this code isn't valid Scala:
val localPackage = for {
failfast <- 1 / 0
} yield failfast
I guess you meant Task.eval(1 / 0).
Also onErrorHandle does not have a Task as a return type, you were probably thinking of onErrorHandleWith. And it's a pretty bad idea to give it a partial function (i.e. a function that can throw exceptions due to matching errors) — if you want to match on that error, then better alternatives are onErrorRecover and onErrorRecoverWith, which take partial functions as arguments.
So here's a sample:
import monix.eval._
import monix.execution.Scheduler.Implicits.global
val task = Task.eval(1 / 0).onErrorRecoverWith {
case _: ArithmeticException => Task.now(Int.MinValue)
}
task.runAsync.foreach(println)
//=> -2147483648
Hope this helps.

Scala waiting for sequence of futures

I was hoping code like follows would wait for both futures, but it does not.
object Fiddle {
val f1 = Future {
throw new Throwable("baaa") // emulating a future that bumped into an exception
}
val f2 = Future {
Thread.sleep(3000L) // emulating a future that takes a bit longer to complete
2
}
val lf = List(f1, f2) // in the general case, this would be a dynamically sized list
val seq = Future.sequence(lf)
seq.onComplete {
_ => lf.foreach(f => println(f.isCompleted))
}
}
val a = FuturesSequence
I assumed seq.onComplete would wait for them all to complete before completing itself, but not so; it results in:
true
false
.sequence was a bit hard to follow in the source of scala.concurrent.Future, I wonder how I would implement a parallel that waits for all original futures of a (dynamically sized) sequence, or what might be the problem here.
Edit: A related question: https://worldbuilding.stackexchange.com/questions/12348/how-do-you-prove-youre-from-the-future :)
One common approach to waiting for all results (failed or not) is to "lift" failures into a new representation inside the future, so that all futures complete with some result (although they may complete with a result that represents failure). One natural way to get that is lifting to a Try.
Twitter's implementation of futures provides a liftToTry method that makes this trivial, but you can do something similar with the standard library's implementation:
import scala.util.{ Failure, Success, Try }
val lifted: List[Future[Try[Int]]] = List(f1, f2).map(
_.map(Success(_)).recover { case t => Failure(t) }
)
Now Future.sequence(lifted) will be completed when every future is completed, and will represent successes and failures using Try.
And so, a generic solution for waiting on all original futures of a sequence of futures may look as follows, assuming an execution context is of course implicitly available.
import scala.util.{ Failure, Success, Try }
private def lift[T](futures: Seq[Future[T]]) =
futures.map(_.map { Success(_) }.recover { case t => Failure(t) })
def waitAll[T](futures: Seq[Future[T]]) =
Future.sequence(lift(futures)) // having neutralized exception completions through the lifting, .sequence can now be used
waitAll(SeqOfFutures).map {
// do whatever with the completed futures
}
A Future produced by Future.sequence completes when either:
all the futures have completed successfully, or
one of the futures has failed
The second point is what's happening in your case, and it makes sense to complete as soon as one of the wrapped Future has failed, because the wrapping Future can only hold a single Throwable in the failure case. There's no point in waiting for the other futures because the result will be the same failure.
This is an example that supports the previous answer. There is an easy way to do this using just the standard Scala APIs.
In the example, I am creating 3 futures. These will complete at 5, 7, and 9 seconds respectively. The call to Await.result will block until all futures have resolved. Once all 3 futures have completed, a will be set to List(5,7,9) and execution will continue.
Additionally, if an exception is thrown in any of the futures, Await.result will immediately unblock and throw the exception. Uncomment the Exception(...) line to see this in action.
try {
val a = Await.result(Future.sequence(Seq(
Future({
blocking {
Thread.sleep(5000)
}
System.err.println("A")
5
}),
Future({
blocking {
Thread.sleep(7000)
}
System.err.println("B")
7
//throw new Exception("Ha!")
}),
Future({
blocking {
Thread.sleep(9000)
}
System.err.println("C")
9
}))),
Duration("100 sec"))
System.err.println(a)
} catch {
case e: Exception ⇒
e.printStackTrace()
}
Even though it is quite old question But this is how I got it running in recent time.
object Fiddle {
val f1 = Future {
throw new Throwable("baaa") // emulating a future that bumped into an exception
}
val f2 = Future {
Thread.sleep(3000L) // emulating a future that takes a bit longer to complete
2
}
val lf = List(f1, f2) // in the general case, this would be a dynamically sized list
val seq = Future.sequence(lf)
import scala.concurrent.duration._
Await.result(seq, Duration.Inf)
}
This won't get completed and will wait till all the future gets completed. You can change the waiting time as per your use case. I have kept it to infinite and that was required in my case.
We can enrich Seq[Future[T]] with its own onComplete method through an implicit class:
def lift[T](f: Future[T])(implicit ec: ExecutionContext): Future[Try[T]] =
f map { Success(_) } recover { case e => Failure(e) }
def lift[T](fs: Seq[Future[T]])(implicit ec: ExecutionContext): Seq[Future[Try[T]]] =
fs map { lift(_) }
implicit class RichSeqFuture[+T](val fs: Seq[Future[T]]) extends AnyVal {
def onComplete[U](f: Seq[Try[T]] => U)(implicit ec: ExecutionContext) = {
Future.sequence(lift(fs)) onComplete {
case Success(s) => f(s)
case Failure(e) => throw e // will never happen, because of the Try lifting
}
}
}
Then, in your particular MWE, you can do:
val f1 = Future {
throw new Throwable("baaa") // emulating a future that bumped into an exception
}
val f2 = Future {
Thread.sleep(3000L) // emulating a future that takes a bit longer to complete
2
}
val lf = List(f1, f2)
lf onComplete { _ map {
case Success(v) => ???
case Failure(e) => ???
}}
This solution has the advantage of allowing you to call an onComplete on a sequence of futures as you would on a single future.
Create the Future with a Try to avoid extra hoops.
implicit val ec = ExecutionContext.global
val f1 = Future {
Try {
throw new Throwable("kaboom")
}
}
val f2 = Future {
Try {
Thread.sleep(1000L)
2
}
}
Await.result(
Future.sequence(Seq(f1, f2)), Duration("2 sec")
) foreach {
case Success(res) => println(s"Success. $res")
case Failure(e) => println(s"Failure. ${e.getMessage}")
}