Writing Scala Verticles

For Verticles to be written in Scala, the base class io.vertx.lang.scala.ScalaVerticle

  • takes care of providing the correct ExecutionContext
  • provides Scala-specific start and stop functions
  • and adds some Scala-specific syntactic sugar
import scala.concurrent.{Future, Promise}
import scala.util.Success

import io.vertx.lang.scala.ScalaVerticle
import io.vertx.lang.scala.ImplicitConversions.*
import scala.language.implicitConversions

final class StartFutureVerticle extends ScalaVerticle:

  // start/stop with Scala Promises
  override def start(promise: Promise[Unit]): Unit =
    promise.complete(Success(()))
  override def stop(promise: Promise[Unit]): Unit =
    promise.complete(Success(()))

  // synchronous start/stop for simple initializations
  override def start(): Unit = {}
  override def stop(): Unit = {}

  // start/stop with Scala Futures
  override def asyncStart: Future[Unit] = Future.unit
  override def asyncStop: Future[Unit] = Future.unit

Deploying Scala Verticles

io.vertx.lang.scala.ScalaVerticle cannot be deployed directly. Instead, we can either use the Verticle's name or convert it to a regular Verticle, using the io.vertx.lang.scala.ScalaVerticle.asJava function.

Standard Deployment

The package io.vertx.lang.scala provides two extensions for the io.vertx.core.Vertx class which allow to deploy ScalaVerticle instances directly, with or without DeploymentOptions:

import io.vertx.core.Vertx
import io.vertx.lang.scala.*
import io.vertx.lang.scala.ScalaVerticle
import scala.concurrent.{Future, Promise}
import scala.util.Success

final class MyVerticle1 extends ScalaVerticle:
  override def start(startPromise: Promise[Unit]): Unit =
    println("MyVerticle1 started")
    startPromise.complete(Success(()))
final class MyVerticle2 extends ScalaVerticle:
  override def start(startPromise: Promise[Unit]): Unit =
    println("MyVerticle2 started")
    startPromise.complete(Success(()))

final class MainVerticle extends ScalaVerticle:

  override def asyncStart: Future[Unit] =
    for {
      _ <- vertx.deployVerticle(MyVerticle1())
      _ <- vertx.deployVerticle(MyVerticle2())
    } yield ()

Deploying via Verticle name

Vertx for Scala brings a VerticleFactory which allows to deploy Scala Verticles by fully-qualified class name. Example:

// package org.example
import io.vertx.core.Vertx
import io.vertx.lang.scala.ScalaVerticle
import io.vertx.lang.scala.ScalaVerticle.nameForVerticle
import scala.concurrent.{Future, Promise}
import scala.util.Success

val vertx = Vertx.vertx()
final class MyVerticle1 extends ScalaVerticle:
  override def start(startPromise: Promise[Unit]): Unit =
    println("MyVerticle1 started")
    startPromise.complete(Success(()))
final class MyVerticle2 extends ScalaVerticle:
  override def start(startPromise: Promise[Unit]): Unit =
    println("MyVerticle2 started")
    startPromise.complete(Success(()))

val deploymentIds = for {
  deploymentId1 <- vertx.deployVerticle(nameForVerticle[MyVerticle1]())
  deploymentId2 <- vertx.deployVerticle("scala:org.example.MyVerticle2")
} yield (deploymentId1, deploymentId2)

Vert.x without Verticles

Although we encourage writing Verticles to create Reactive Applications, Vert.x can also be used entirely without Verticles. Doing so in Scala is just as easy as in Java.

When dealing with Futures, Scala requires to define an scala.concurrent.ExecutionContext for operations like map or filter. Verticles, on the other hand, have their own context which they need so Vert.x can properly schedule all the tasks belonging to a Verticle, for example sending messages over the EventBus.

Vertx for Scala brings the io.vertx.lang.scala.VertxExecutionContext which takes care to move all tasks to the correct Vert.x thread bound by the Vert.x context. Typically, we define VertxExecutionContext as given (Scala 2: implicit).

The following examples shows how to bootstrap a simple Hello-World HTTP server in a simple main function.

import io.vertx.core.Vertx
import io.vertx.lang.scala.*
import scala.concurrent.Future
import scala.util.{Failure, Success}

@main def main: Unit =
  val vertx = Vertx.vertx
  given exec: VertxExecutionContext = VertxExecutionContext(vertx, vertx.getOrCreateContext())
  
  vertx
    .createHttpServer
    .requestHandler(_.response.end("Hello world!"))
    .listen(8080).asScala
    .onComplete {
      case Success(_) => println("Success")
      case Failure(_) => println("Failure")
    }

Also note the call to the extension method asScala which is defined in package io.vertx.lang.scala. This is an alternative to the implicit conversion io.vertx.lang.scala.ImplicitConversions.vertxFutureToScalaFuture. This can be used in situations where implicit conversions cannot be applied, for example the code above.