How to do: Try {block of code} for X duration and catch {Exceptions, such as Timeout}? - scala

Alright so the title is a little obscure since I was unsure how to word it, but essentially I am trying to do a try-catch statement that will timeout... Here's some pseudo-code that may help describe what I'm trying to do:
try (10 seconds) {
*make some connection and do some things*
} catch {
case ex1: TimeoutException => *do something*
case ex2: Exception => *do something else*
}
Currently there is a bug in the hardware I'm working with where the request for a connection never gets a response back, so it just sits there and doesn't catch any exceptions. Since it's only a bug (that should be temporary), I don't want to manipulate the architecture of the application (specifically I do not want to create a new actor just to account for something small) and it would be very ideal if I could implement this pseudo-code within the scope of the class.
So essentially my question is how do I implement the pseudo-code above within the scope of the class it's in?
Let me know if anything is unclear! Thank you!

Try:
import scala.concurrent._
import ExecutionContext.Implicits.global
val f = future {
// make some connection and do some things
}
try {
Await.result(f, 10 seconds);
} catch {
case e: TimeoutException => // do something
case _ => // do something else
}
More info: Futures and Promises

Related

mapping future not working in play controller

I have a play controller:
def createBlokPost() = Action { implicit request =>
val postvals: Option[Map[String, Seq[String]]] = request.body.asFormUrlEncoded
postvals.map { args =>
val email = args("email").head
val name = args("name").head
val population = args("population").head
val location = args("location").head
val studentRequirements = args("Student Requirements").head
val schoolFundingMethod = args("School funding method").head
val createSchool = modelPersistent.createSchool(email, name, population.toShort, location, studentRequirements.toShort, schoolFundingMethod.toShort)
var workedVal = false
createSchool.map { thing =>
thing match {
case Some(i) => workedVal = true
case None => workedVal = false
}
}
if (workedVal) {
Ok("It frickin worked!")
} else {
Ok("Something went wrong on our end :( \nYour school may already have a Blok.")
}
}.getOrElse(Ok("Oops. You're a loser. Something went wrong and we cannot help you because in reality... we dont care enough. \nImagine being such a loser that something went wrong on the sign up page 😂.\n\nBTW. Every time this happens I get a notification telling me that someone fucked up and do you know what I do? I laugh knowing that there is some degenerate out there with the ability to fail so quickly."))
}
createSchool is a future[option[Int]]. In my test project this is working so I believe it to be an issue with putting it in the controller. The error I am receiving is:
[error] a.a.ActorSystemImpl - Uncaught error from thread [application-akka.actor.default-dispatcher-10]
scala.runtime.NonLocalReturnControl: null
I do not know what this means but the controller is still completing meaning that the row is added to the database and it returns "Something went wrong on our end :( \nYour school may already have a Blok.". I have also tried a flatMap and onComplete but neither of those are working. Additionally, I tried making the action async but it would not compile.
The issue is that it is not changing the boolean workedVal and it is always returning false even if it is working.
Any help would be greatly appreciated.
What is happening is basically:
the Future result of createSchool(...) is bound to createSchool
workedVal is initialized to false
a callback is attached to createSchool
workedVal is checked and false
Ok with the error message is returned
The createSchool Future completes
The callback is executed, possibly setting workedVal
You'll have to make it an async Action, which means every path has to result in a Future
So something like this should work
postvals.map { args =>
// the args lookups... they're a bit hinky, but setting that aside
modelPersistent.createSchool(email, name, population.toShort, location, studentRequirements.toShort, schoolFundingMethod.toShort)
.map { createResult =>
if (createResult.isDefined) Ok("It frickin' worked!")
else Ok("Something went wrong on our end :( \nYour school may already have a Blok.")
}
}.getOrElse {
Future.successful(Ok("Oops. You're a loser. Something went wrong and we cannot help you because in reality... we dont care enough. \nImagine being such a loser that something went wrong on the sign up page 😂.\n\nBTW. Every time this happens I get a notification telling me that someone fucked up and do you know what I do? I laugh knowing that there is some degenerate out there with the ability to fail so quickly."))
}

How to catch exception in future in play framework 2.4

I'm trying to figure out how to catch an exception from within a future in a function being called by an asynchronous action in Play Framework 2.4. However, the code I've got using recover never seems to get executed - I always get an Execution exception page rather than an Ok response.
The action code is:
def index = Action.async {
cardRepo.getAll()
.map {
cards => Ok(views.html.cardlist(cards))
}.recover{
case e: Exception => Ok(e.getMessage)
}
}
The code in cardRepo.getAll (that I've hard-coded a throw new Exception for experimenting) is:
def getAll(): Future[Seq[Card]] = {
implicit val cardFormat = Json.format[Card]
val cards = collection.find(Json.obj())
.cursor[Card]()
.collect[Seq]()
throw new Exception("OH DEAR")
cards
}
I've seen similar questions on Stack Overflow but I can't see what I'm doing wrong.
Thanks Mon Calamari - I think I understand now. The future is coming from collection.find, so if an error was inside that, my code would work but because I've put I've got it inside the function above it, there is no Future at that point.

Consuming a service using WS in Play

I was hoping someone can briefly go over the various ways of consuming a service (this one just returns a string, normally it would be JSON but I just want to understand the concepts here).
My service:
def ping = Action {
Ok("pong")
}
Now in my Play (2.3.x) application, I want to call my client and display the response.
When working with Futures, I want to display the value.
I am a bit confused, what are all the ways I could call this method i.e. there are some ways I see that use Success/Failure,
val futureResponse: Future[String] = WS.url(url + "/ping").get().map { response =>
response.body
}
var resp = ""
futureResponse.onComplete {
case Success(str) => {
Logger.trace(s"future success $str")
resp = str
}
case Failure(ex) => {
Logger.trace(s"future failed")
resp = ex.toString
}
}
Ok(resp)
I can see the trace in STDOUT for success/failure, but my controller action just returns "" to my browser.
I understand that this is because it returns a FUTURE and my action finishes before the future returns.
How can I force it to wait?
What options do I have with error handling?
If you really want to block until feature is completed look at the Future.ready() and Future.result() methods. But you shouldn't.
The point about Future is that you can tell it how to use the result once it arrived, and then go on, no blocks required.
Future can be the result of an Action, in this case framework takes care of it:
def index = Action.async {
WS.url(url + "/ping").get()
.map(response => Ok("Got result: " + response.body))
}
Look at the documentation, it describes the topic very well.
As for the error-handling, you can use Future.recover() method. You should tell it what to return in case of error and it gives you new Future that you should return from your action.
def index = Action.async {
WS.url(url + "/ping").get()
.map(response => Ok("Got result: " + response.body))
.recover{ case e: Exception => InternalServerError(e.getMessage) }
}
So the basic way you consume service is to get result Future, transform it in the way you want by using monadic methods(the methods that return new transformed Future, like map, recover, etc..) and return it as a result of an Action.
You may want to look at Play 2.2 -Scala - How to chain Futures in Controller Action and Dealing with failed futures questions.

Difference between Promise.failure and throwing exception?

Is there any difference between these two ways of completing a failed Future? If so, which way is considered to be more "correct"?
Calling Promise.failure:
def functionThatFinishesLater: Future[String] = {
val myPromise = Promise[String]
Future {
// Do something that might fail
if (failed) {
myPromise.failure(new RuntimeException("message")) // complete with throwable
} else {
myPromise.success("yay!")
}
} (aDifferentExecutionContext)
myPromise.future
}
Or just throwing an exception
def functionThatFinishesLater: Future[String] = {
val myPromise = Promise[String]
Future {
// Do something that might fail
if (failed) {
throw new RuntimeException("message") // throw the exception
} else {
myPromise.success("yay!")
}
} (aDifferentExecutionContext)
myPromise.future
}
It looks to me like you're mixing paradigms. A Promise is an imperative way of completing a Future, but a Future can also be made completed by wrapping the computation in a Future constructor. You're doing both, which is probably not what you want. The second statement in both code fragments is of type Future[Promise[String]], and I'm almost certain you really want just Future[String].
If you're using using the Future.apply constructor, you should just treat the value produced as the Future, rather than using it to resolve a separate Promise value:
val myFuture = Future {
// Do some long operation that might fail
if (failed) {
throw new RuntimeException("message")
} else {
"yay!"
}
}
The way to use the Promise is to create the Promise, give its Future to some other piece of code that cares, and then use .success(...) or .failure(...) to complete it after some long running operation. So to recap, the big difference is that Future has to wrap the whole computation, but you can pass a Promise around and complete it elsewhere if you need to.

How to make Play print all the errors

In our Scala, Play, Reactivemongo we have a big problem with exception handling - when there is an error, in Iteratee/Enumeratee or in Actor system Play just swallows it, without logging any error to the output. So we effectively need to guess where, and why this error might happen.
We made Globals override, to always print the error, and specified logger.root=TRACE, but still saw no output, from which we could analyse our problems.
How to forcebly make Play print all the errors
Didn't found the way to explicitly log everything but there is a way to log exceptions locally.
I did this:
def recover[T] = Enumeratee.recover[T] {
case (e, input) => Logger.error("Error happened on:" + input, e)
}
and then used it on all the enumeratees that can produce errors
def transform(from: Enumerator[From]): Enumerator[String] = {
heading >>> (from &> recover[From] ><> mapper) >>> tailing
}
here, mapper throws exception, and they are all logged.
I think your problem is with how Future works in scala, let's take the following exemple :
val f :Future[Int]= Future {
throw new NullPointerException("NULL")
1
}
f.map(s1 => {println(s" ==> $s1");s" ==> $s1"})
This code will throw an exception but the stack trace will not be printed as futures handle the error.
If you want to get the error that happened you can
just call:
f.onComplete{
case Success(e) => {}
case Failure(e) => e.printStackTrace()
}
e is a throwable that you can use as you want to handle the error.
At the solution I used, is override through ErrorHandling in Play https://www.playframework.com/documentation/2.4.2/ScalaErrorHandling, basically creating ErrorHandler that logs all the errors, with needed detalization.