Getting data out of a Future in Scala - scala

I've a Future[List[Person]][1] and I want to get the List[Person] from it. How can I do it ?
import scala.concurrent.Future
val futPersons : Future[List[Person]] = ....

There are multiple ways:
futPersons.map { personList =>
....
}
This map returns another Future composed with whatever you return from the map. The map will execute only if the future completes successfully. If you need to handle failure you can use onComplete
futPersons.onComplete {
case Success(personList) => ...
case Failure(exception) => ...
}
Or you can wait for the future to complete (this is blocking):
val personList: List[Person] = Await.result(futPersons, 1 minutes)

Blocking way (pauses your thread until you get the value back) using Await.result:
scala.concurrent.Await.result(futPersons, timeout)
Or, using a callback with onSuccess:
futPersons onSuccess {
case persons => // do something with persons
}

Related

Avoid syncronous calls in Akka Actors due of Await result

Because I do some "complex" operations, I think my Actor became asyncronous. The main problem I think is that I use Await.result inside the method which return responses.
actor:
def process(subscribers: Set[ActorRef]): Receive = {
case Join(ref) => context become process(subscribers + ref)
case Leave(ref) => context become process(subscribers - ref)
case Push(request) =>
val filteredSubscribers = (subscribers - sender())
.filter(s => exists(s, request)) // just some actor filters
filteredSubscribers.foreach { subscriber =>
// here I have a Map with each actor requests
val actorOptions = getActorOptions(subscriber)
subscriber ? getResponse(actorOptions, request)
}
}
The problem is inside getResponse (I think).
getResponse(actorOptions: JsValue, request: SocketRequest): JsValue = {
(actorOptions \ "dashboardId").asOpt[Int] match {
case Some(id) => {
val response = widgetsService.getByDashboadId(id) map { widgets =>
val widgetsResponse: List[Future[String]] = widgets.map(w => {
widgetsService.getDataById(w.id) map {
data => s"""{ "widgetId": ${w.id}, "data": $data }"""
}
})
var responses: List[String] = List.empty
widgetsResponse.foreach(f => {
f.onComplete {
case Success(value) => responses = value :: responses
case Failure(e) => println(s"Something happened: ${e.getMessage}")
}
})
// first time when I use Await.result
// used to populate the responses list with data from all futures
Await.result(Future.sequence(widgetsResponse), Duration.Inf)
Json.parse(s"""{
"dashboardId": $id,
"widgets": [${response.mkString(", ")}]
}""".stripMargin)
}
// second time when I use Await.result
// used to return a JsValue instead of a Future[JsValue]
Await.result(response, Duration.Inf)
}
case None => buildDefaultJson // return default json value, unimportant for this example
}
}
Due of that, In frontend, if I have 2 sockets clients, the response for the second will be send only after first.
I found that I can obtain a "fake" increase of performance if I embrance the getResponse in a future inside of my Actor.
filteredSubscribers.foreach { subscriber =>
val actorOptions = getActorOptions(subscriber)
Future(subscriber ? getResponse(actorOptions, request))
}
So, for both subscribers the action will be started in same time, but when the first will reach the Await.result, the second will be locked until first is done.
I need to avoid using Await.result there, but I don't know how to get the results of a list of futures, without using for-comprehension (because is a dynamically list) for first time where I use it.
Because Akka ask operator (?) return a Future[Any], I tried that my getResponse method to return directly a JsValue to be mapped then in Future[JsValue]. If I remove the second Await.result and my method will return Future[JsValue], then the actor will return a Future[Future[JsValue]] which I don't think is too right.
After some more researches and solutions found on so, my code become:
Future.sequence(widgetsResponse) map { responses =>
Json.parse(
s"""
|{
|"dashboardId": $id,
|"tableSourceId": $tableSourceId,
|"widgets": [ ${responses.mkString(", ")}]
|}""".stripMargin
)
}
getResponse returns a Future[JsValue] now, removing both Await.result cases, and actor case become:
filteredSubscribers.foreach { subscriber =>
val actorOptions = getActorOptions(subscriber)
getResponse(actorOptions, request) map { data =>
subscriber ? data
}
}
I don't know why, still have a synchronous behavior. Damn, this can be due of my subscribers type: Set[ActorRef]? I tried to use parallel foreach and this looks like solving my problem:
filteredSubscribers.par.foreach { subscriber =>
val actorOptions = getActorOptions(subscriber)
getResponse(actorOptions, request) map { data =>
subscriber ? data
}
}

How to return a value of Future when its done?

I wrote a simple method that returns List of Int based on a service call i perform in it.
my problem is that the service call im making is returning a future of some value, so I thought i can do onComplete and return what I want on complete of the future, but onComplete returns Unit...
this is how I wanted it to work:
def getListOfInts(str: String): List[Int] = {
myDaoService.findSomethingInDb(str).onComplete {
case Success(res) =>
res.map(line => line.amount.toInt*100).distinct.filter(num => num != 0).toList
case Failure(exception) => logger.error(s"finding in db has failed with exeption: ", exception)
}
}
what is the right way to return the wanted value of a future when it completed?
i know usually its map/flatmap but this will keep it wrapped in the future and I want my method to return the actual value and not future of the value...
thanks!
Await.result is the way to go, but Its not recommended.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.Await
def getListOfInts(str: String): List[Int] = {
Await.result(myDaoService.findSomethingInDb(str), 10 seconds).map(line => line.amount.toInt*100).distinct.filter(num => num != 0).toList
}
The above way is not recommended until and unless you want to make the thread of execution wait(block) for the result. The above code does not scale.
Recommended way
def getListOfInts(str: String): Future[List[Int]] =
myDaoService.findSomethingInDb(str).map { res =>
res.map(line => line.amount.toInt*100).distinct.filter(num => num != 0).toList
}
The recommended way is to compose the future (use map and flatmap to transform the output type of the database call into the required result) and then finally doing waiting to get the final transformed result.
http://docs.scala-lang.org/overviews/core/futures.html
onComplete, onSuccess and onFailure are the callbacks you are looking for

Getting the value out of a Future in Scala

I have the following code snippet that I use to read a record from the database and I'm using ReactiveMongo for this.
val futureList: Future[Option[BSONDocument]] = collection.find(query).cursor[BSONDocument].headOption
val os: Future[Option[Exam]] = futureList.map {
(list: Option[BSONDocument]) => list match {
case Some(examBSON) => {
val id = examBSON.getAs[Int]("id").get
val text = examBSON.getAs[String]("text").get
val description = examBSON.getAs[String]("description").get
val totalQuestions = examBSON.getAs[Int]("totalQuestions").get
val passingScore = examBSON.getAs[Int]("passingScore").get
Some(Exam(id, text, description, totalQuestions, passingScore))
}
case None => None
}
}.recover {
case t: Throwable => // Log exception
None
}
I do not want to change my method signature to return a Future. I want to get the value inside the Future and return it to the caller.
You need then to block using the awaitable object:
import scala.concurrent.duration._
val os: Future[Option[Exam]] = ???
val result = Await.result(os, 10 seconds)
result.getOrElse(/* some default */)
Note that blocking will block the thread until the future is completed or the timeout expires and an exception is thrown, note also that this kinda defeats the purpose of having async computation, but it may be ok depending on your use case.
If you don't need the result immediately you can attach a callback using onComplete
os onComplete {
case Success(someOption) => myMethod(someOption)
case Failure(t) => println("Error)
}
Note that onComplete will be fired only when the future is completed so the result is not immediately accessible, also the return type is Unit.

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.

Scala return result from a Promise

Looking to achieve this:
HTTP request to REST API -> parse -> make async call to another API -> respond to http req with the result of the async call.
Currently, the code looks like:
def getItems(param: String): LiftResponse = {
#volatile var resp: LiftResponse = new BadResponse
param.toLowerCase match {
case "something" =>
val req = Async call returning a Future
req onSuccess {
case items =>
resp = new JsonResponse(items map (decompose(_)), S.getResponseHeaders(Nil), S.responseCookies, 200)
}
req onFailure {
case fail => resp = new BadResponse
}
resp
case _ => new OkResponse
}
}
But it looks like poor implementation.
What is the idiomatic Scala way to write the above?
Your code will probably not do what you think it should since it depends on scheduling whether it returns null or something else. Is LiftResponse a strict value or can it be deferred? If strict then you will have to return a Future[LiftResponse] obtained by mapping your req: Future.
Look into using Lift's RestHelper in conjunction with RestContinuation.async. It supports using continuations to suspend a request until data is available for it. There's some sample code at http://demo.liftweb.net/async_rest . After the async continuation is invoked and before the reply function is called with the result, the request thread will be released to the thread pool. Once the reply function is called, the request will be put back on a thread and the response sent to the client.
I think you can try to inline #volatile var resp by:
def getItems(param: String): LiftResponse = {
param.toLowerCase match {
case "something" =>
val req = Async call returning a Future
req.onComplete {
case Success(items) => new JsonResponse(items map (decompose(_)), S.getResponseHeaders(Nil), S.responseCookies, 200)
case Failure(t) => new BadResponse
}
case _ => new OkResponse
}
}
--edit--
sorry, onComplete returns Unit, how about using Await to get the result of future:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.concurrent.duration._
def getItems(param: String): LiftResponse = {
param.toLowerCase match {
case "something" =>
val req = Async call returning a Future
val response = req map { items =>
new JsonResponse
} recover {
case t:Throwable => new BadResponse
}
Await.result(response, Duration(100, MILLISECONDS))
case _ => new OkResponse
}
}
Note (3 years later): with the recent (Nov. 2016) release of Lift3, you can use net.liftweb.http._, as described in "Request and Session Access in Lift Futures", from Piotr Dyraga.
As an example, say that you want to lazily render a list of users.
First, you execute database query asynchronously and get Future[Seq[User]] as a result of this operation.
If you use Lift 2, incorporate FutureBinds that I described in one my previous posts or if you use Lift3, import net.liftweb.http._ and do:
val allUsers: Future[Seq[User]] = ... // retrieve users from DB
".user-list-async-container" #> allUsers.map { users =>
".user-list" #> users.map { user =>
".user" #> userBindings(user)
}
}