So far we’ve made a lot of promises 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 promises are broken.
Breaking promises is 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 happens, and how bad it can get.
import dispatch._
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 it hasn’t completed yet so we don’t know that it failed:
str: dispatch.Promise[String] = Promise(-incomplete-)
If we have the console print its string representation a moment later, we’ll get a different result:
scala> str
res0: dispatch.Promise[String] = Promise(!Unexpected response status: 302!)
But we still have a promise of string. So 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.
Broken promises carry their exceptions through transformations:
scala> for (s <- str) yield s.length
res7: dispatch.Promise[Int] = Promise(!Unexpected response status: 302!)
Applying it would yield the same result as before.
And if you ask for operations on the completed promise, the exception will be thrown into the background thread assigned to it.
scala> for (s <- str) println(s)
scala> [error] (AsyncHttpClient-Callback) java.lang.Error:
java.util.concurrent.ExecutionException: dispatch.StatusCode:
Unexpected response status: 302
...
Broken promises must throw exceptions, but exceptions in asynchronous programming are worse than ugly: they are unmanageable. How can we safely build on promises that depend on uncertain network operations?
The solution is to avoid breaking promises and throwing exceptions by planning for failure. In the next pages we’ll see very simple and very rich ways of doing that.