Don't Use Await.result!

Posted on 19 February 2019

Almost regularly I see Scala code where people program in a sequential, synchronous style and integrate an asynchronous I/O call by waiting for its completion with Await.result. But you really shouldn’t.

Let me start with a quote from Viktor Klang, the author of the Scala Futures library:

Why is Await.result bad?

If you call Await.result, you invoke a blocking operation to wait for a non-blocking one. From an efficiency point of view, this is – madness.

It’s as if Alice makes a phone call to Bob to get some information. Bob needs to get the information from Charlie and sends him a text message. While Bob continues with his daily business until he gets a message from Charlie back, Alice stays on the phone the whole time, just waiting until Bob has received the message and passes the information on to her. Obviously this is a waste of Alice’s time. For an unnecessarily long period, it keeps her from doing something meaningful.

What should I do instead?

Stay „inside“ the Future! If you call a method that returns a Future, also return a Future from your method. Execute the code you want to execute after Await.result on completion of the Future (using one of the many combinators, e.g. foreach / map / flatMap / onComplete / transform). From Akka actors, use pipeTo.

To quote Roland Kuhn: „consider every Await.result() to be a bug unless carefully justified“.

The Twitter Scala School (unfortunately) uses Await.result in their example code, but read what they write just underneath:

“In practice, you won’t write code that sends a request and then calls Await.result() a few statements later. A Future has methods to register callbacks to invoke when the value becomes available.”

“When you use Futures in real code, you normally don’t call Await.result(); you use callback functions instead.”

But I need to make sure the operation completes in n milliseconds?

Await.result has a timeout parameter (atMost), which seems a convenient way of imposing a maximum waiting time for an asynchronous operation to complete. But you should look for different ways to enforce a timeout. Outgoing calls should be wrapped in circuit breakers. You can then set the timeout on the circuit breaker. Even without circuit breakers, e.g. Finagle client lets you set a timeout, as does Play WS Client, as does akka.ask, etc. If you use Akka, use the scheduler to send a message after a given time, or use akka.pattern.after.

If it’s not a call to another system, and you don’t use Akka, you can start another Future that sleeps for a while before throwing an exception, and use Future.firstCompletedOf. This is not great, but still preferable to Await.result, as at least you don’t block the calling thread, which may be one of a limited pool for dispatching HTTP requests or the like. And from a type perspective, as you’ll still have a Future as the result of your operation.
If you need this often, you might want to implement a TimeoutScheduler (I haven’t used it myself, but will try it next time I need to timeout Futures).
I’d love to hear other suggestions, what do you use in your code to enforce timeouts?

So maybe I should just not use async clients for HTTP calls, DB access etc. at all, just use blocking ones, to keep my code simple?

No! No no no! Asynchronous I/O is the way to go, for scalability and efficient resource usage. Blocking I/O is a waste of resources. Never block! Async all the things! Seriously. See for example the presentation Need for Async: Hot pursuit for scalable applications.
To add to that, instead of „wrapping“ a non-blocking call in a blocking one (which you should really never do), you should do the opposite! If you have an intrinsically blocking call (e.g. JDBC), you should wrap it in a Future. This way, you can make sure it’s executed in a controlled environment, by providing a separate ExecutionContext dedicated to blocking I/O operations.

But my use case is much more complicated..

The observations I made so far in my customers’ codebases where just async calls to external systems, wrapped in Await.result to make them appear synchronous. You may have different scenarios, where you have a mix of synchronous and asynchronous operations, and some state you need to track, and the need to spawn many Futures to do things concurrently, etc. In this case you might want to move to a different abstraction altogether, possibly Akka actors. If you feel you really must use Await.result in your code, you should post an example in Scala Users and get some feedback there - I’m quite sure people will come up with better alternatives.

There is no rule without exceptions.

I can think of only two legitimate use cases of Await.result:

In tests

That’s ok, although for example with ScalaTest 3 or later you shouldn’t even have to use it there.

If you need to override a method of a superclass or a trait you must implement (and consequently must provide the required return type).

Then you don’t really have a choice, do you? But before falling back to Await.result you should double-check if there isn’t a better way.

  • If you have control over the superclass/trait, change the signature to return a Future.
  • If you don’t, do you really have to implement that particular method, or is there an alternative (e.g. in Spring MVC change to returning a DeferredResult)?

If there is a need to go from asynchronous to synchronous, there is a mismatch between framework philosophies. You should attempt to replace the synchronous / blocking framework with an asynchronous / non-blocking one.

When you really have to, for example because you have to run on a pre-3.0 Servlet container that doesn’t provide any asynchronous support, make sure to make an explicit choice where and why you call Await.result. In this synchronous, thread-per-request servlet scenario, pass the Future all the way up to the controller and call Await.result only in the very end to return the response from the controller method. This way it becomes clear what demands the blocking, and so you can easily and quickly refactor it when you update to a better HTTP layer.


If you'd like to learn Scala and learning from a book is what works for you, I recommend to get one of these two:

Programming in Scala by Martin Odersky et al.
Programming Scala by Dean Wampler
Categories:
  • Scala

Share this article on: