3

I have the following code in Scala:

val status: Future[String] = Await.ready(Http(address OK as.String), 1 second)

I'm making a http call and I'm waiting for an answer for a second.

I was told it's not good practice to block using Await.ready.

I'm curious what I can use instead.

Can I use for comprehensions? How?

bsky
  • 19,326
  • 49
  • 155
  • 270

2 Answers2

3

It generally bad to block on an asynchronous operation, otherwise, why make it asynchronous at all?

You can use various implementations with Future[T], such as registering a continuation to invoke when the result arrives. For example, let's assume you want to parse the String result into a Foo object. You'd get:

val result: Future[Foo] = Http(address OK as.String).map {
  s => parseJson[Foo](s)
}

Note that when working with Future[T], you'll end up bubbling them up the call chain of the execution, unless you synchronously block.

Same can be achieved with for comprehension:

for {
 s <- Http(address OK as.String)
} yield (parseJson[Foo](s))
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • Thanks! I would like to wait for a limited amount of time though(for instance, maximum 1 second). How can I do that? – bsky Dec 12 '16 at 13:58
  • @octavian [This answer](http://stackoverflow.com/a/16305056/1870803) shows you how to add an extension of timeout to a `Future`. – Yuval Itzchakov Dec 12 '16 at 14:18
2

Using Await.ready is not a good practice because its blocking. In most of the cases you can compose and transform the futures to achieve the desired result.

But You can use blocking when its absolutely necessary. Here is my answer about blocking and its consequences When to and when not use blocking

Non-Blocking wait

def afterSomeTime(code: => Unit)(duration: FiniteDuration): Unit = {
  someActorSystem.scheduler.scheduleOnce(duration) {
    code
  }
} 

Above function will call the code after given duration, you can use any other timer implementation instead of Akka scheduler

case class TimeoutException(msg: String) extends Exception(msg)

def timeout[T](future: => Future[T])(duration: FiniteDuration)(implicit ec: ExecutionContext): Future[T] = {

  val promise = Promise[T]()
  future.onComplete(promise tryComplete)

  afterSomeTime {
    promise tryFailure TimeoutException(s"Future timeout after ${duration.toString()}")
  }(duration)

  promise.future
}
Community
  • 1
  • 1
Nagarjuna Pamu
  • 14,737
  • 3
  • 22
  • 40