scalahttpfinagletwitter-finagle

Finagle quickstart client


I have a bare sbt project to which I have added "com.twitter" %% "finagle-http" % "6.33.0". I am following the quickstart guide for Twitter Finagle. The code I have is a direct copy-paste:

import com.twitter.finagle.{Http, Service}
import com.twitter.finagle.http
import com.twitter.util.{Await, Future}

object Client extends App {
  val client: Service[http.Request, http.Response] = Http.newService("www.scala-lang.org:80")
  val request = http.Request(http.Method.Get, "/")
  request.host = "www.scala-lang.org"
  val response: Future[http.Response] = client(request)
  response.onSuccess { resp: http.Response =>
    println("GET success: " + resp) 
    println(resp.contentString)    // modification 1
  }
  Await.ready(response)
  println("needed this")           // modification 2
}

Without "modification 2" I get no output at all. With that println added, I get

needed this
GET success: Response("HTTP/1.1 Status(200)")

Process finished with exit code 0
  1. Why didn't the response print without "modification 2"?
  2. Why is there is no contentString printed from "modification 1"?

If I set a breakpoint on "modification 1", and evaluate resp.contentString using the current state, the HTML for the website is returned as desired.

How can I get that to print while the program is running normally?


Solution

  • The signature of the onSuccess method on Twitter's Future is different from the one on the standard library's Future—instead of this:

    def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit
    

    You have this:

    def onSuccess(f: (A) ⇒ Unit): Future[A]
    

    I.e. it returns a new future that returns the same value as the old future, but also performs a side effect, instead of just performing the side effect. (As a side note, in my view this is one of the many ways the Twitter future API is better than the standard library's—I prefer both the fact that the function argument's return type is Unit and that the method's isn't).

    What's happening in your case is that the threads Finagle is using for the client are daemonized, so if you don't explicitly await the result of a future, there's no guarantee that the JVM won't exit before that future is satisfied. Changing your code to await the result of the future returned by onSuccess will make everything work as expected.