Jan Vladimir Mostert
Jan Vladimir Mostert

Reputation: 12972

Building non-blocking VertX server with CoroutineVerticle

I'm experimenting with VertX+Couroutines and just want to check if this setup is blocking at any point or has potential issues that i need to be aware of.

For example, is runBlocking being used correctly in this instance or should i rather do a deployVerticle? And then inside requestHandler, i'm doing GlobalScope.launch, this seems to be discouraged, what is the correct scope to use here?

I've added VertX 4.0.0-milestone5 to my Gradle build script, i'm not using VertX Web:

            val vertxVersion = "4.0.0-milestone5"
            implementation("io.vertx:vertx-core:$vertxVersion") {
                exclude(group = "com.fasterxml.jackson.core", module = "jackson-core")
                exclude(group = "com.fasterxml.jackson.core", module = "jackson-databind")
                exclude(group = "log4j", module = "log4j")
                exclude(group = "org.apache.logging.log4j", module = "log4j-api")
                exclude(group = "org.apache.logging.log4j", module = "log4j-core")

            }
            implementation("io.vertx:vertx-lang-kotlin:$vertxVersion")
            implementation("io.vertx:vertx-lang-kotlin-coroutines:$vertxVersion")

Inside Routing.kt i have the following setup:

class Routing(
    private val port: Int
) : CoroutineVerticle() {

    override suspend fun start() {

        Vertx.vertx().createHttpServer(
            HttpServerOptions().setCompressionSupported(true)
        ).requestHandler { req ->
            GlobalScope.launch {
                try {

                    log.info("${req.method()}:${req.path()}")

                    req.response().setStatusCode(200).end("Hello World")
                } catch (e: Exception) {
                    log.error(e.message ?: "", e)
                    req.response().setStatusCode(500).end("Something Went Wrong")
                }
            }
        }.listen(port)

        log.info("Listening on $port")

    }


    override suspend fun stop() {

    }

    companion object {

        private val log = LoggerFactory.getLogger(Routing::class.java)
        private val root = RoutingTree()

        suspend fun setup(port: Int) {
            Endpoint.all.forEach {
                root.addPath(it.key, it.value)
            }
            log.info("\n" + root.toString())
            Routing(port = port).start()
        }
    }

}

This Routing.setup is then used inside main()

object Server {

    private val log = LoggerFactory.getLogger(this.javaClass)

    @JvmStatic
    @ExperimentalTime
    fun main(args: Array<String>) = runBlocking {

        ....

        // setup routing
        Routing.setup(
            port = if (ENV.env == LOCAL) {
                5555
            } else {
                80
            },
        ) 

Upvotes: 0

Views: 753

Answers (1)

Alexey Soshin
Alexey Soshin

Reputation: 17701

The whole point of Kotlin integration with Vert.x is that you don't have to use GlobalScope.launch

Here's a minimal example of how it can be achieved:

fun main() {
    val vertx = Vertx.vertx()

    vertx.deployVerticle("Server")
}

class Server : CoroutineVerticle() {
    override suspend fun start() {
        vertx.createHttpServer().requestHandler { req ->
            // You already have access to all coroutine generators
            launch {
                // In this scope you can use suspending functions
                delay(1000)
                req.response().end("Done!")
            }
        }.listen(8888)
    }
}

Upvotes: 2

Related Questions