JamieP
JamieP

Reputation: 1794

Nesting Futures in Play Action

Im using Play and have an action in which I want to do two things:-

  1. firstly check my cache for a value
  2. secondly, call a web service with the value

Since WS API returns a Future, I'm using Action.async.
My Redis cache module also returns a Future.

Assume I'm using another ExecutionContext appropriately for the potentially long running tasks.

Q. Can someone confirm if I'm on the right track by doing the following. I know I have not catered for the Exceptional cases in the below - just keeping it simple for brevity.

def token = Action.async { implicit request =>


    // 1. Get Future for read on cache

    val cacheFuture = scala.concurrent.Future {   
        cache.get[String](id)    
    }


    // 2. Map inside cache Future to call web service

    cacheFuture.map { result =>   

        WS.url(url).withQueryString("id" -> result).get().map { response =>
            // process response
            Ok(responseData)
        }

    }

}

My concern is that this may not be the most efficient way of doing things because I assume different threads may handle the task of completing each of the Futures.

Any recommendations for a better approach are greatly appreciated.

Upvotes: 1

Views: 242

Answers (1)

cchantep
cchantep

Reputation: 9168

That's not specific to Play. I suggest you have a look at documentations explaining how Futures work.

val x: Future[FutureOp2ResType] = futureOp1(???).flatMap { res1 => futureOp2(res1, ???) }

Or with for-comprehension

val x: Future[TypeOfRes] = for {
  res1 <- futureOp1(???)
  res2 <- futureOp2(res1, ???)
  // ...
} yield res

As for how the Futures are executed (using threads), it depends on which ExecutionContext you use (e.g. the global one, the Play one, ...).

WS.get returning a Future, it should not be called within cacheFuture.map, or it will returns a Future[Future[...]].

Upvotes: 3

Related Questions