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:
- Should I use the vertx execution context with all my futures in verticles ?
- Same question for worker verticles.
- 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.