Scala return result from a Promise - scala

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)
}
}

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
}
}

rendering a page after Future is done with Play2

Using Play2 framework with Slick DB manager, I have a class that encapsulates DB access, and a controller in charge of returning that information to the user. There are roughly like this:
Class with DB access:
override def getAllAnswersFuture(userID: Int): Future[List[UserAnswer]] = {
(DB QUERY CREATION AS allAnswersQuery)
val myquery : Future[Seq[(Int, String)]] =myDB.run(allAnswersQuery.result)
myquery.map{x => x.map(elem =>(
UserAnswer(elem._1, elem._2).toList}
}
Controller:
def index = Action { request =>
request.session.get("userID").map { userID =>
val myUser = userStorage.getUser(userID.toInt)
val allAnswersFuture = questionStorage.getAllAnswersFuture(myUser.id)
allAnswersFuture onComplete {case _ => Ok(views.html.app.stats())}
Ok(views.html.app.index("Future did not work"))
}.getOrElse {
Unauthorized("Oops, you are not connected")
}
}
For some reason, the content of onComplete is never shown, returning the "future did not work" instead.
My question is, How do I tell Play2 to wait until the DB query has been completed and then print the results?
Use Action.async for dealing with futures and try doing something like:
def index = Action.async { request =>
allAnswersFuture.map{_ => Ok(views.html.app.stats())}.recover {
case ex: Exception =>
Ok(views.html.app.index("Future did not work"))
}
}
Instead of using onComplete on future use Map and recover, If you want to return anything on future callback. OnComplete on Future won't return anything, Its return type is Unit.
In case of Future success, your stats page will be populated and in failure index page will be populated from recover block.
And in your getOrElse block use:
Future.successful(Unauthorized("Oops, you are not connected"))
This will do the needful

Handling Future[WSResponse] to find success or error state

In Scala I have a call to service in controller which is returning me Future[WSResponse]. I want to make sure service is returning valid result so send Ok(..) otherwise send BadRequest(...). I don't think I can use map. Any other suggestion?
def someWork = Action.async(parse.xml) { request =>
val result:Future[WSResponse] = someService.processData(request.body.toString())
//Need to send back Ok or BadRequest Message
}
EDIT
Solution from #alextsc is working fine. Now moving to test my existing test is failing. It is getting 400 instead of 200.
test("should post something") {
val requestBody = <value>{UUID.randomUUID}</value>
val mockResponse = mock[WSResponse]
val expectedResponse: Future[WSResponse] = Future.successful(mockResponse)
val request = FakeRequest(Helpers.POST, "/posthere").withXmlBody(requestBody)
when(mockResponse.body).thenReturn("SOME_RESPONSE")
when(someService.processData(any[String])).thenReturn(expectedResponse)
val response: Future[Result] = call(controller.someWork , request)
whenReady(response) { response =>
assert(response.header.status == 200)
}
}
You're on the right track and yes, you can use map.
Since you're using Action.async already and your service returns a future as it stands all you need to do is map that future to a Future[Result] so Play can handle it:
def someWork = Action.async(parse.xml) { request =>
someService.processData(request.body.toString()).map {
// Assuming status 200 (OK) is a valid result for you.
case resp : WSResponse if resp.getStatus == 200 => Ok(...)
case _ => BadRequest(...)
}
}
(I note that your service returns WSResponse (from the play ws java library) and not play.api.libs.ws.Response (the scala version of it), hence getStatus and not just status)

Use Future in Spray Routing

I'm new to asynchronous programming. I read this tutorial http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html and was surprised by how effortless I can incorporate Future into the program. However, when I was using Future with Routing, the return type is kind of wrong.
get {
optionalCookie("commToken") {
case Some(commCookie) =>
val response = (MTurkerProgressActor ? Register).mapTo[..].map({...})
val result = Await.result(response, 5 seconds)
setCookie(HttpCookie("commToken", content = result._2.mturker.get.commToken)) {
complete(result._1, result._2.mturker.get)
}
case None => // ...
}
}
I really don't want to use Await (what's the point of asynchronous if I just block the thread and wait for 5 seconds?). I tried to use for-comprehension or flatMap and place the setCookie and complete actions inside, but the return type is unacceptable to Spray. For-comprehension returns "Unit", and flatMap returns a Future.
Since I need to set up this cookie, I need the data inside. Is Await the solution? Or is there a smatter way?
You can use the onSuccess directive:
get {
optionalCookie("commToken") { cookie =>
//....
val response = (MTurkerProgressActor ? Register).mapTo[..].map({...})
onSuccess(response) {
case (result, mTurkerResponse) =>
setCookie(HttpCookie("commToken", content = mTurkerResponse.mturker.get.commToken)) {
complete(result, mturkerResponse.mturker.get)
}
}
}
There's also onFailure and onComplete (for which you have to match on Success and Failure) See http://spray.io/documentation/1.2.1/spray-routing/future-directives/onComplete/
Also, instead of using get directly it's much more idiomatic to use map (I assume the mturker is an Option or something similar):
case (result, mTurkerResponse) =>
mTurkerResponse.mturker.map { mt =>
setCookie(HttpCookie("commToken", content = mt.commToken)) {
complete(result, mt)
}
}
You can also make a custom directive using this code -
case class ExceptionRejection(ex: Throwable) extends Rejection
protected def futureDirective[T](x: Future[T],
exceptionHandler: (Throwable) => Rejection = ExceptionRejection(_)) =
new Directive1[T] {
override def happly(f: (::[T, HNil]) => Route): Route = { ctx =>
x
.map(t => f(t :: HNil)(ctx))
.onFailure { case ex: Exception =>
ctx.reject(exceptionHandler(ex))
}
}
}
Example usage -
protected def getLogin(account: Account) = futureDirective(
logins.findById(account.id)
)
getAccount(access_token) { account =>
getLogin(account) { login =>
// ...
}
}

Getting data out of a Future in 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
}