Future does not complete reliably in Play Framework - scala

A piece of code using Play Framework 2.3
def signup = Action(parse.json) { implicit request =>
val email = (request.body \ "email").asOpt[String]
val holder =
WS.url("https://foobar.com/foo")
.withAuth("1234","5678",WSAuthScheme.BASIC)
val data = Json.obj(
"email" -> email,
)
holder.post(data)
Ok("OK")
}
This code will perform the post() when run locally on my machine, but not reliably on remote machines. From my understanding the post() call should create and return a future, signup() returns Ok(), the future is run on the default ExecutionContext and at some point completes and is cleaned up. Apparently this is not the case.
I have since changed the function to be an Action.async and am now waiting on the Future:
val res = holder.post(data)
res.map( x => Ok(Json.obj("status" -> "OK"))) recover {
case (e: Exception) =>
InternalServerError(Json.obj("status" -> "Not OK."))
}
This works reliably. Hence, my questions:
Why does the first version not work reliably?
How can I in general "fork off" a long running procedure, without intention of waiting on it, purely for its side-effects, if not like I did in version 1?

It's near impossible to say why the Future isn't completing "reliably", but I'd hazard a guess that there's something wrong with the web service you're trying to reach. SSL problems, timeouts not being reached,.. the possibilities are large without knowing what exception is being thrown (if any?).
If you don't want to wait on the WS call, you can use the onComplete callback:
val res = holder.post(data)
res.onComplete {
case Success(response) =>
// Create some side-effect to the response
case Failure(e) =>
// The `Future` failed.
}

Related

How to correctly do error handling that involves asynchronous methods

Suppose I have the following methods defined in some service used in my Play application each of which executes some command, on failure, updates database and sends some notification asynchronously.
def thisMightFail(): Future[SomeResult]
def thisUpdatesStatus(): Future[Unit]
def thisSendsNotification(): Future[Unit]
thisUpdatesStatus and thisSendsNotification are independent of each other and are called for error handling like the below. (No further execution is possible on failure)
for {
_ <- Future{ Some process }
result <- thisMightFail() transform {
case Success(v) => v
case Failure(cause) =>
val f = Future.sequence(List(
thisUpdatesStatus(),
thisSendsNotification()
))
Failure(new Exception("Command execution failed", cause))
}
_ <- Future{ Another process that uses "result" }
:
} yield ...
My question is should the f be waited before returning Failure(cause) or is there some better way to handle the error in this kind of situation?
My question is should the f be waited before returning Failure(cause)
or is there some better way to handle the error in this kind of
situation
Currently your code does not handle failure of thisUpdatesStatus() and thisSendsNotification(). are you ok with the failure of these functions call ? I suspect it will not be ok if thisMightFail() fails and you do not update the database. Also user should receive some notification if thisMightFail() fails.
You should use a workflow platform for such cases such as cadence . You can find a nice introduction of cadence here.

scala: playframework controller action execution sequence with future

I am having problem with my play-framework API server. I need to have some processing running in the background that is returning a Future with the result and then write the result as response. However, the request thread goes all out and return before my Future completes. Here is the code...
def requestAction(): Action[AnyContent] = Action.async { implicit request =>
var fResult: Future[String] = Future { "initial value" }
try {
fResult = doSomethingAsyncAndGetResponseString(); // return "great, everything is done"
}
catch {
case t: Throwable {
fResult = Future { "failed" }
}
}
// done, return response, but the problem is, this is executed first because doSomethingAsyncAndGetResponseString() is still executing and returns later
fResult.map( res => {
// problem here, because I get "initial value" which is not what I want
Ok(res)
}
}
Is there a way to get "great, everything is done" or "failed" without Async.await ? I have been using this format all over in my API server, but today it broke because in a new API that I write, the doSomethingAsyncAndGetResponseString is a bit longer. I didn't expect that, so something must be wrong with how I understand the structure.
Thanks in advance!
You are trying to write Java like code using Scala.
You are doing it wrong. Read about Futures and How to use them.
Here is the tutorial
Futures can be composed using map and flatMap constructs. recover and recoverWith will give the user access to exception happened in the computation pipeline
You have to do something like this, given below
def requestAction(): Action[AnyContent] = Action.async { implicit request =>
Future { "initial value" }.flatMap { _ =>
doSomethingAsyncAndGetResponseString() // returns Future
}.map { res =>
Ok(res)
}.recover { case th =>
Ok(th.getMessage)
}
}
Handling exceptions and recovering from exceptions
Exception handling is inbuilt into Future.
recover gives access to exception and also helps the user to provide the alternative success value in case of exception.
recoverWith gives access to an exception and also helps the user to provide/chain alternative Future computation which can succeed or fail.
Future {
throw new Exception("foo exception")
}.recover {
case th => println(s"msg: ${th.getMessage}")
}

How to handle response timeout?

In akka-http routing I can return Future as a response that implicitly converts to ToResponseMarshaller.
Is there some way to handle timeout of this future? Or timeout of connection in route level? Or one way is to use Await() function?
Right now client can wait response forever.
complete {
val future = for {
response <- someIOFunc()
entity <- someOtherFunc()
} yield entity
future.onComplete({
case Success(result) =>
HttpResponse(entity = HttpEntity(MediaTypes.`text/xml`, result))
case Failure(result) =>
HttpResponse(entity = utils.getFault("fault"))
})
future
}
Adding a timeout to an asynchronous operation means creating a new Future that is completed either by the operation itself or by the timeout:
import akka.pattern.after
val future = ...
val futureWithTimeout = Future.firstCompletedOf(
future ::
after(1.second, system.scheduler)(Future.failed(new TimeoutException)) ::
Nil
)
The second Future could also hold a successful result that replaces the error, depending on what exactly it is that you want to model.
As a side note: the presented code sample contains dead code, registering an onComplete handler on a Future only makes sense for side-effects but you seem to want to transform the Future’s value and create an HttpEntity from it. That should be done using map and recover:
future
.map(result => HttpResponse(entity = HttpEntity(MediaTypes.`text/xml`, result)))
.recover { case ex => HttpResponse(entity = utils.getFault("fault")) }
This would then be the overall return value that is passed to the complete directive.

Do Play! 2 Action.async requests kill the future in the background when interrupted?

I've got the following Play! 2 Action.async controller:
def complexAlgorithm(graphId: String) = Action.async { implicit request =>
val f = future {
val data = new ComplexAlgorithm(GraphContext.get(graphId))
data.evaluate
data
}
f.map { result => Ok(Json.generate(result.getRankings.toList.filterNot(o => o.rankScore == 0))) }
}
I've realized that in some cases this computation is actually going to take more than an hour. Since this will be redesigned for production use, I'm OK with waiting for the result in the browser since it's logged anyways.
So my question is does the future above val f get killed if the browser request is interrupted? Say for instance, if the internet disconnects while waiting for a response? Or will it actually complete its calculation (even if hours later)?
Thanks!

How should I wait for a scala dispatch (0.11.0) http get request to be completed?

I'm using the scala dispatch (0.11.0) library to send an HTTP GET request to a remote server. I want to wait for the response before executing the code which follows the request.
My request is of the form :
val req = :/("myurl.com") <:< myheaders OK as.Response(identity)
If I write :
val future = http(req)
future()
var res: String = null
future onComplete {
case Success(r) => res = r.getResponseBody
case _ => println("KO")
}
println(res)
I get null.
This is also the case if I write :
val future = http(req)
var res: String = null
while (!future.isCompleted) {
Thread.sleep(1000)
}
future onComplete {
case Success(r) => res = r.getResponseBody
case _ => println("KO")
}
println(res)
But with the following code :
val future = http(req)
var res: String = null
future onComplete {
case Success(r) => res = r.getResponseBody
case _ => println("KO")
}
while (!future.isCompleted) {
Thread.sleep(1000)
}
println(res)
I get the expected response.
Does someone understand this ?
It seems to me that calling Thread.sleep is not a good thing, could someone give me a hint on how I should handle this problem correctly ?
EDIT: #Randal Schulz thank you for your help, but as you posted in comments, I can't validate your answer.
As my problem was to wait (and do nothing else) until I get a valid response to an HTTP GET request, I think a satisfying way to do it is using Await.result. I removed the side-effect from my code. I used the option method to deal with Future failures (as I was interested only in successes), and I dealt with time out exception the classic way.
I think I could do it as wheaties mentionned, staying in Future, but I need more practice...
TL;DR
The best advice I can give you for working in an asynchronous work flow is that what goes into a Future stays in a Future.
Answer
The issue is that you have no idea when the Future will complete so if you want to use an asynchronous process, you're going to have to write in an asynchronous manner. The code as you have written never stops or blocks on the Future you create so the minute it creates the Future and hand it off to another thread, the current thread is free to then evaluate the res variable.
Hence, place most of what you're doing in a flow like follows:
myFuture map (func1) map (func2) map (func3) onComplete{
case Success(value) => println(value.getResponseBody)
case _ => println('KO')
}
Don't attempt to access something via side-effect like you are.
If you're really clever and you have several Future you can compose them:
val f1 = myFuture map(func1)
val f2 = myOtherFuture map(func2) map (func3)
val f3 = for{
v1 <- f1
v2 <- f2
} yield functionTakingBoth(v1, v2)
f3 onComplete{
//and do stuff here
}
I finally managed to write what I wanted using futures :
def loop(): Future[String] = {
val future = http(req).option
future flatMap ((x: Option[Response]) => x match {
case Some(rep) => rep.getResponseBody
case None => loop()
}
}
Now I can use the result of this function without explicitely waiting for the response to come.