Vert.x
Node for the JVM
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/47239/smartthings_physical_graph.jpg)
WHOAMI
Ryan Applegate
@rappleg
https://github.com/rappleg
Developer @ SmartThings
Grails Developer - 4+ years
Java Background - 7 years
What is Node?
Server Side Javascript
Event Driven Non-Blocking I/O
Single thread/single event loopApplication registers handlersEvents trigger handlersEverything runs on the event loop
Node is Not Web Scale
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/46552/mongo_db_web_scale.jpg)
Why Vert.x?
Same event-driven non-blocking IO programming model as Node
Polyglot (Groovy, Ruby, Java, Javascript, Python, Scala and Clojure coming soon)Mature concurrency framework (JVM)Hazelcast for Clustering
Interprocess Communication via Event Bus
Asynchronous & Effortlessly Scalable
Vert.x Caveat
Benchmark #1
Benchmark #2
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45030/vertx_benchmark_2.png)
Verticle
Vert.x Instance
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45089/white-left-arrow.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
-instances 4
Running Vert.x Server
vertx.createHttpServer().requestHandler { req ->
def file = req.uri == "/" ? "index.html" : req.uri
req.response.sendFile "webroot/$file"
}.listen(8080)
vertx run Server.groovy
vertx run Server.groovy -instances 32
Running Vert.x Server (runmod)
vertx runmod server-mod -instances 32
Concurrency
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
Event Bus Addressing
Handler Registration
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45138/white_arrow_down_left.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45113/white_arrow_left.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45136/white_arrow_up_left.png)
Handler Registration
def eb = vertx.eventBus()
eb.registerHandler("test.address") { message ->
println "I received a message ${message.body}"
}
Pub/Sub
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45138/white_arrow_down_left.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45113/white_arrow_left.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45136/white_arrow_up_left.png)
Pub/Sub
Deliver single message to all handlers registered at an address
eb.publish("test.address", "hello world")
P2P
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45138/white_arrow_down_left.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45113/white_arrow_left.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45136/white_arrow_up_left.png)
P2P
Deliver message to only one handler registered at an address
eb.send("test.address", "hello world")
P2P Messaging Options
Implement replyHandler for messages
Sender
eb.send("test.address", "Some message") { message ->
println "I received a reply ${message.body}"
}
Receiver
eb.registerHandler("test.address") { message ->
println "I received a message ${message.body}"
// Do some work here
message.reply("Some reply")
}
Message Types
- String
- Primitives
- Boxed Primitives
- Boolean
- java.util.map - representing JSON
- org.vertx.java.core.JsonObject
- org.vertx.java.core.Buffer
Vert.x in the Browser
SockJS Server
def server = vertx.createHttpServer()
server.requestHandler { req ->
if (req.uri == "/")
req.response.sendFile("index.html")
if (req.uri.endsWith("vertxbus.js"))
req.response.sendFile("vertxbus.js")
}.listen(8080)
def sockJSServer = vertx.createSockJSServer(server)
sockJSServer.bridge( { prefix: "/eventBus"} )
server.listen(8080)
SockJS Client
<script src="http://cdn.sockjs.org/sockjs-0.2.1.min.js"></script>
<script src="vertxbus.js"></script>
<script>
var eb = new vertx.EventBus('http://localhost:8080/eventBus')
eb.onopen = function() {
eb.registerHandler('msgs.echo', function(message) {
alert('Echoing msg: ' + JSON.stringify(message))
});
}
WebSockets on the Server
def server = vertx.createHttpServer()
server.websocketHandler{ ws ->
println "A websocket has connected!"
}.listen(8080, "localhost")
Rejecting WebSockets
def server = vertx.createHttpServer()
server.websocketHandler{ ws ->
if (ws.path == "/services/echo") {
Pump.createPump(ws, ws).start()
} else {
ws.reject()
}
}.listen(8080, "localhost")
WebSockets on the HTTP Client
def client = vertx.createHttpClient()
client.connectWebsocket("http://localhost:8080/some-uri") { ws ->
// Connected!
}
WebSockets in the browser
<script>
var socket = new WebSocket("ws://localhost:8080/services/echo");
socket.onmessage = function(event) {
alert("Received data from websocket: " + event.data);
}
socket.onopen = function(event) {
alert("Web Socket opened");
socket.send("Hello World");
};
socket.onclose = function(event) {
alert("Web Socket closed");
};
</script>
Vert.x Shared State
Allowed Values
- Strings
- Boxed Primitives
- byte[]
- org.vertx.java.core.buffer.Buffer
-
org.vertx.java.core.shareddata.Shareable
Shared Map
Verticle 1
def map = vertx.sharedData.getMap('demo.mymap')
map["some-key"] = 123
Verticle 2
def map = vertx.sharedData.getMap('demo.mymap')
// Retrieve value 123 from the map
def value = map."some-key"
Shared Set
Verticle 1
def set = vertx.sharedData.getSet('demo.myset')
set << "some-value"
Verticle 2
def set = vertx.sharedData.getSet('demo.myset')
// Set will now contain some-value
set.contains("some-value")
Reactor Pattern Issues
- MUST not block the event loop
-
Some work is natually blocking
- Intensive data crunching
- 3rd-party blocking API's (e.g. JDBC, etc...)
-
Node.js is not good for this type of work
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45085/event_loop_icon.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45476/BG_POOL.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45476/BG_POOL.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/rappleg/images/45106/up_down_arrow.gif)
Worker Verticle Example
public class FibWorker extends Verticle {
@Override
public void start() {
def eb = vertx.eventBus()
eb.registerHandler("fib.request") { message ->
def result = fib(message.body.intValue())
def resultMessage = { nbr: message.body,
result: result }
eb.send("fib.response", resultMessage)
}
}
def fib(n) { n < 2 ? 1 : fib(n-1) + fib(n-2) }
}
Verticle (Running on Event Loop)
public class WorkerExample extends Verticle {
@Override
public void start() {
def eb = vertx.eventBus()
eb.registerHandler("fib.response") { msg ->
println "Fib:${msg.body.nbr}=${msg.body.result}"
}
container.deployWorkerVerticle("worker.FibWorker")
{ msg ->
eb.send("fib.request", 20)
}
}
}
More stuff with Vert.x Core APIs
- TCP/SSL servers and clients
- HTTP/HTTPS servers and clients
- WebSockets servers and clients
- Accessing the distributed event bus
- Periodic and one-off timers
- Buffers
- Flow control
- Accessing files on the file system
- Shared map and sets
- Logging
- Accessing configuration
- Writing SockJS servers
-
Deploying and undeploying verticles
How do I contribute to Vert.x?
How does SmartThings use Vert.x?
SmartThings Vert.x Throughput
~6 million events/day from hubs to Vert.x
Vert.x Common Mistake
vertx.createHttpServer(someHttpServerConfig).requestHandler { request ->
def responseString = "ERROR" try { // Do some stuff with the request responseString = "OK" } catch (Exception e) {
responseString = "ERROR (${e.getClass().name})"
} finally {
request.response.end("${responseString}") } }.listen(someHttpServerConfig.port)
Resources
VERT.X
By rappleg
VERT.X
- 7,512