What's new in Vert.x 4.5
Vert.x 4.5 comes a couple of new exciting features.
Here is an overview of the most important features and changes supported in Vert.x 4.5.
Virtual threads
Java 21 has finally brought virtual threads to Java and you can use them right now in Vert.x to write code that looks like it is synchronous.
You still write the traditional Vert.x code processing events, but you have the opportunity to write synchronous code for complex workflows and use thread locals in such workflows.
A virtual thread verticle is capable of awaiting Vert.x futures and gets the result synchronously.
Vert.x virtual threads can block on any Vert.x future using await
:
You can find more in our example repo.
Dynamic SQL connection creation
By default, a connection pool always connects to the same host, in other words the database config is static.
Sometimes database config needs to be dynamic, e.g. connecting to an array of databases or the database config can change.
With dynamic connection configuration you can easily implement this in Vert.x:
Each time the pool needs to create a connection, the options supplier is called and the returned options is used to create the connection.
PG bouncer transaction pooling mode
Level 7 proxies can load balance queries on several connections to the actual database. When it happens, the client can be confused by the lack of session affinity and unwanted errors can happen like ERROR: unnamed prepared statement does not exist (26000).
Vert.x SQL client now supports Level 7 proxies like PgBouncer.
TCP SSL options update
You can now update TCP client/server SSL options at runtime which is very useful for certificate rotation.
New connections will use the updated configuration.
WebSocket client
We have captured the WebSocket client API from Vert.x HTTP client in a new WebSocket client.
This purpose of this change is to let the HttpClient
interface focus on HTTP interactions
and clean up the interface.
Client builders
We start to introduce the builder pattern for advanced client creation in 4.5.
The builder pattern facilitates the configuration and creation of Vert.x clients when they need to be configured beyond options.
HTTP client builder
Most of the time you will create an HTTP client using the good old createHttpClient
method.
Sometimes you want to configure the client with extra behavior like setting a connection handler or a redirect handler: the HTTP client builder provides these extra configuration capabilities.
This enforces the configuration of handlers at creation time and produces an immutable client with its configuration and handlers.
The fact is Vert.x 5 will provide more configuration capabilities like a client side load balancer and address resolver.
SQL connection pool builder
Vert.x SQL client pool creation uses per database static pool creation methods, e.g.
PgPool#create
.
There are a couple of good reasons to get away from PgPool
like interfaces:
- those interfaces extend
Pool
but they never add new methods - configuring extra behaviour like
connectHandler
is not well suited
The latter is well suited when extra behavior is needed like setting a connectHandler
.
Redis command tracing
The Redis client can trace command execution when Vert.x has tracing enabled.
The client reports a client span with the following details:
- operation name: Command
- tags:
- db.user: the database username, if set
- db.instance: the database number, if known (typically 0)
- db.statement: the Redis command, without arguments (e.g. get or set)
- db.type: redis
Traffic shaping
TCP server (net/HTTP) can be configured with traffic shaping options to enable bandwidth limiting.
Vert.x API extensions for coroutines
The Vert.x EventBus
and MessageConsumer
objects are extended with support for coroutines inside a coroutineEventBus
scope function:
The scope function is not necessary if the surrounding type implements io.vertx.kotlin.coroutines.CoroutineEventBusSupport
.
For example, with a coroutine verticle:
Similarly, the Vert.x Web Router
and Route
objects are extended with support for coroutines inside a coroutineRouter
scope function:
Again, the scope function is not necessary if the surrounding type implements io.vertx.kotlin.coroutines.CoroutineRouterSupport
.
For example, with a coroutine verticle: