A future of success and failure 

So far we’ve made a lot of futures depending on network operations that might fail, and remote services that may not care for our input. If things don’t go as planned, the futures will fail.

Failed futures 

Failed futures are messy. You may have already seen the mess created in playing around with the previous examples. Here we’ll make a big mess to see what happens, and how bad it can get.

import dispatch._, Defaults._
val str = Http(host("example.com") OK as.String)

So far, so good? We’ve made a request that will fail the OK test with a redirect status code, but this failure hasn’t happened yet from the software’s perspective.

Future#print for failed futures 

If we have the console print its string representation a moment later, we’ll see the problem:

scala> str.print
res0: String = Future(!Unexpected response status: 302!)

Applying failed futures 

But we’re still holding have a future of string. What happens if we demand the string?

scala> str()
dispatch.StatusCode: Unexpected response status: 302
    at dispatch.OkHandler$class.onStatusReceived(handlers.scala:37)
    at dispatch.OkFunctionHandler.onStatusReceived(handlers.scala:29)

The exception was thrown in the thread that demanded the value, since there is no way to supply it.

Transforming broken futures 

Broken futures carry their exceptions through transformations:

val length = for (s <- str) yield s.length

Printing yields the same result as before.

res54: String = Future(!Unexpected response status: 302!)

Deferred failed futures 

And if you ask for operations on the completed future, nothing happens.

scala> for (s <- str) println(s)

How can we safely build on futures that depend on uncertain network operations?

Planning for failure 

The solution is to avoid breaking futures and throwing exceptions by planning for failure. In the next pages we’ll see very simple and very rich ways of doing that.

Fork me on GitHub