1
votes

In an attempt to get out of nested callbacks hell, at least for readability, I am using Scala futures in my vertx application.

I have a simple verticle handling HTTP requests. Upon receiving a request, the verticle calls a method doing async stuff and returning a Future. On future completion, HTTP response is sent to the client:

class HttpVerticle extends Verticle with VertxAccess {
    val routeMatcher = RouteMatcher()

    routeMatcher.get("/test", request => {      
        println(Thread.currentThread().getName)
        // Using scala default ExecutionContext
        import scala.concurrent.ExecutionContext.Implicits.global

        val future = getTestFilePath()
        future.onComplete {
            case Success(filename) => {
                println(Thread.currentThread().getName)
                request.response().sendFile(filename)
            }
            case Failure(_) => request.response().sendFile("/default.txt")
        }
    })

    def getTestFilePath(): Future[String] = {
        // Some async stuff returning a Future
    }
}

I noticed that using the usual (at least for me) ExecutionContext, the thread executing the completion of the future is not part of the vertx pool (this is what the prinln statement is for). The first prinln outputs vert.x-eventloop-thread-4 whereas the second outputs ForkJoinPool-1-worker-5.

Then, I supposed I had to use instead the vertx execution context:

class HttpVerticle extends Verticle with VertxAccess {
    val routeMatcher = RouteMatcher()

    routeMatcher.get("/test", request => {      
        println(Thread.currentThread().getName)
        // Using vertx execution context
        implicit val ec: ExecutionContext = VertxExecutionContext.fromVertxAccess(this)

        val future = getTestFilePath()
        future.onComplete {
            case Success(filename) => {
                println(Thread.currentThread().getName)
                request.response().sendFile(filename)
            }
            case Failure(_) => request.response().sendFile("/default.txt")
        }
    })

    def getTestFilePath(): Future[String] = {
        // Some async stuff returning a Future
    }
}

With this, the first and second println will output vert.x-eventloop-thread-4.

Note that this is a minimal example. In my real application code, I have multiple nested callbacks and thus chained futures.

My questions are:

  1. Should I use the vertx execution context with all my futures in verticles ?
  2. Same question for worker verticles.
  3. If the answers to the above questions are yes, is there a case where, in a vertx application, I should not use the vertx application context ?

Note: I am using vertx 2.1.5 with lang-scala 1.0.0.

1

1 Answers

1
votes

I got an answer from Lars Timm on the vert.x Google user group :

Yes, you should use the Vertx specific execution context. That ensures the futures are run on the correct thread/event loop. I haven't tried it with worker verticles but I don't see why it shouldn't work there also.

By the way, you should consider using the 1.0.1-M1 instead of 1.0.0. As far as I remember an error was fixed in the ExecutionContext in that version. You also don't have to import the VertxExecutionContext. It's automatically done when you inherit from Verticle/VertxAccess.