Slide 1

Slide 1 text

Applications réactives avec Eclipse Vert.x Devoxx France 2017 Julien Ponge Julien Viet

Slide 2

Slide 2 text

Julien Ponge Maitre de Conférences “Delegated consultant to Red Hat” on Vert.x (part-time) Eclipse Golo + extensive F/OSS background ! https://julien.ponge.org/ " @jponge # @jponge  https://www.mixcloud.com/hclcast/

Slide 3

Slide 3 text

Julien Viet Open source developer for 15+ years Current @vertx_project lead Principal software engineer at Marseille Java User Group Leader ! https://www.julienviet.com/ # http://github.com/vietj " @julienviet  https://www.mixcloud.com/cooperdbi/

Slide 4

Slide 4 text

Agenda Introduction Vert.x core 101 Networking with Vert.x Boiler Vroom % & ' Guests ( ) * Ecosystem RxJava Outro

Slide 5

Slide 5 text

Eclipse Vert.x Open source project started in 2012 Created by Tim Fox Eclipse / Apache licensing A toolkit for building reactive applications for the JVM ! https://vertx.io " vertx_project

Slide 6

Slide 6 text

Installation Java 8 Vert.x is a set of jars on Maven Central Unopinionated : your build, your IDE CLI vertx tool

Slide 7

Slide 7 text

Let’s build our first reactive app!

Slide 8

Slide 8 text

Reactive Non blocking Event driven Distributed Reactive programming

Slide 9

Slide 9 text

Vert.x Modular Minimum dependencies Composable Embedded

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Vert.x Un-opinionated Classloading free, IoC free Simple Flows

Slide 12

Slide 12 text

Vert.x core — 101

Slide 13

Slide 13 text

Outline ✓ Vert.x concurrency model ✓ Dealing with asynchronous events ✓ Message passing on the event bus ✓ Failover demo

Slide 14

Slide 14 text

Vert.x Concurrency Model

Slide 15

Slide 15 text

while (isRunning) { String line = bufferedReader.readLine(); switch (line.substring(0, 4)) { case "ECHO": bufferedWriter.write(line); break // ... // other cases ( ...) // ... default: bufferedWriter.write("UNKW Unknown command"); } }

Slide 16

Slide 16 text

x 1000 = +

Slide 17

Slide 17 text

String line = bufferedReader.readLine(); switch (line.substring(0, 4)) { case "ECHO": bufferedWriter.write(line); break // (…) , C1 C2

Slide 18

Slide 18 text

C1 “When you have a line of text, call C2” Something else with no blocking call either C2

Slide 19

Slide 19 text

Events Thread Event Loop

Slide 20

Slide 20 text

Reactor Multi-reactor

Slide 21

Slide 21 text

 2 event-loops per CPU core by default

Slide 22

Slide 22 text

 Verticles . . . public class SomeVerticle extends AbstractVerticle { @Override public void start() throws Exception { } @Override public void stop() throws Exception { } } class SomeVerticle : AbstractVerticle() { override fun start() { } override fun stop() { } } exports.vertxStart = function() { } exports.vertxStop = function() { }

Slide 23

Slide 23 text

. / Configuration . . Network events come from acceptor threads Verticle Deploy Deploy

Slide 24

Slide 24 text

. Worker thread pool Blocking task 0 executeBlocking Result

Slide 25

Slide 25 text

. “Regular verticle” (on event-loop) 0 . Worker verticle (1 thread) Multi-thread worker verticle . Worker pool

Slide 26

Slide 26 text

Dealing with asynchronous events

Slide 27

Slide 27 text

@FunctionalInterface public interface Handler { void handle(E event); } doSomething("localhost", 8080, value -> { // ( ..) });

Slide 28

Slide 28 text

AsyncResult if (asyncResult.succeeded()) { Object result = asyncResult.result(); // ( ...) } else { Throwable t = asyncResult.cause(); // ( ...) } 1 2

Slide 29

Slide 29 text

vertx.createHttpServer() .requestHandler(req -> req.response().end("Yo!")) .listen(8080, ar -> { if (ar.failed()) { System.err.println("Wooops!"); } });

Slide 30

Slide 30 text

vertx.createHttpServer() .requestHandler(req -> req.response().end("Yo!")) .listen(8080, ar -> { if (ar.failed()) { System.err.println("Wooops!"); } }); Handler

Slide 31

Slide 31 text

vertx.createHttpServer() .requestHandler(req -> req.response().end("Yo!")) .listen(8080, ar -> { if (ar.failed()) { System.err.println("Wooops!"); } }); Handler>

Slide 32

Slide 32 text

Future AsyncResult Handler>

Slide 33

Slide 33 text

Future aFuture = Future.future(); // ( ...) // Much much later, in another galaxy aFuture.complete(“Awesome!"); 1

Slide 34

Slide 34 text

Future aFuture = Future.future(); // ( ...) // Much much later, in another galaxy aFuture.fail("Wooops"); 2

Slide 35

Slide 35 text

public void doSomethingAsync(Handler> handler) { // ( ...) handler.handle( Future.succeededFuture("Yeah!") ); // ( ...) } Passing a success result

Slide 36

Slide 36 text

public void doSomethingAsync(Handler> handler) { // ( ...) handler.handle( Future.failedFuture(new IOException("Broken pipe"))); // ( ...) } Passing a failure result

Slide 37

Slide 37 text

Handler> completer = aFuture.completer(); An async result handler that completes a future

Slide 38

Slide 38 text

Future f1 = Future.future(); Future f2 = f1 .compose(str -> Future.succeededFuture(str.length())) .map(n -> n * 2) .otherwise(0) .setHandler(ar -> { if (ar.succeeded()) { System.out.println(ar.result()); } else { ar.cause().printStackTrace(); } }); f1.complete("abc");

Slide 39

Slide 39 text

Future f1 = Future.future(); Future f2 = f1 .compose(str -> Future.succeededFuture(str.length())) .map(n -> n * 2) .otherwise(0) .setHandler(ar -> { if (ar.succeeded()) { System.out.println(ar.result()); } else { ar.cause().printStackTrace(); } }); f1.complete("abc");

Slide 40

Slide 40 text

Future f1 = Future.future(); Future f2 = f1 .compose(str -> Future.succeededFuture(str.length())) .map(n -> n * 2) .otherwise(0) .setHandler(ar -> { if (ar.succeeded()) { System.out.println(ar.result()); } else { ar.cause().printStackTrace(); } }); f1.complete("abc");

Slide 41

Slide 41 text

Future f1 = Future.future(); Future f2 = f1 .compose(str -> Future.succeededFuture(str.length())) .map(n -> n * 2) .otherwise(0) .setHandler(ar -> { if (ar.succeeded()) { System.out.println(ar.result()); } else { ar.cause().printStackTrace(); } }); f1.complete("abc");

Slide 42

Slide 42 text

Future f1 = Future.future(); Future f2 = f1 .compose(str -> Future.succeededFuture(str.length())) .map(n -> n * 2) .otherwise(0) .setHandler(ar -> { if (ar.succeeded()) { System.out.println(ar.result()); } else { ar.cause().printStackTrace(); } }); f1.fail(new IllegalStateException("Just won't do"));

Slide 43

Slide 43 text

List futures = Arrays.asList( Future.succeededFuture("Ok"), Future.failedFuture("Bam"), Future.succeededFuture("Great") ); CompositeFuture.all(futures);

Slide 44

Slide 44 text

List futures = Arrays.asList( Future.succeededFuture("Ok"), Future.failedFuture("Bam"), Future.succeededFuture("Great") ); CompositeFuture.join(futures);

Slide 45

Slide 45 text

List futures = Arrays.asList( Future.succeededFuture("Ok"), Future.failedFuture("Bam"), Future.succeededFuture("Great") ); CompositeFuture.any(futures);

Slide 46

Slide 46 text

Message passing on the event bus

Slide 47

Slide 47 text

. . Http server verticle Database client verticle  ?

Slide 48

Slide 48 text

. 5 . Http server verticle Database client verticle  Event Bus 6 “Details for user 1234?” Send to “user.db”

Slide 49

Slide 49 text

. 5 . Http server verticle Database client verticle  Event Bus 6 “Details for user 1234?” Send to “user.db” Consume from “user.db”

Slide 50

Slide 50 text

. 5 . Http server verticle Database client verticle  Event Bus 6 5 “Details for user 1234?” “{data}”

Slide 51

Slide 51 text

6 Asynchronous messaging “foo.bar”, “foo-bar”, “foo/bar”, … Point to point (with possible response back) Publish / subscribe

Slide 52

Slide 52 text

6 Distributed across Vert.x nodes Hazelcast, Ignite, Infinispan, … TCP bridge interface Go, Python, C, JavaScript, Swift, C#, … SockJS bridge Seamless frontend / backend messaging

Slide 53

Slide 53 text

vertx.eventBus().consumer("a.b.c", message -> { System.out.println(message.body()); }); . . . . vertx.setPeriodic(1000, id -> { vertx.eventBus().send("a.b.c", "tick"); }); 5 5

Slide 54

Slide 54 text

vertx.eventBus().consumer("a.b.c", message -> { System.out.println(message.body()); }); . . . . vertx.setPeriodic(1000, id -> { vertx.eventBus().publish("a.b.c", "tick"); }); 5 5 5 5

Slide 55

Slide 55 text

5 Headers DeliveryOptions (e.g., timeouts) Body Address Reply address

Slide 56

Slide 56 text

5 “Primitive” types String, int, double, … JSON Object/Array Polyglot applications, clean boundaries Custom codecs For advanced usages

Slide 57

Slide 57 text

switch (message.headers().get("action")) { case "all-pages": fetchAllPages(message); break; case "get-page": fetchPage(message); break; case "create-page": createPage(message); break; case "save-page": savePage(message); break; case "delete-page": deletePage(message); break; default: message.fail(ErrorCodes.BAD_ACTION.ordinal(), "Bad action: " + action); }

Slide 58

Slide 58 text

private void deletePage(Message message) { dbClient.getConnection(car -> { if (car.succeeded()) { SQLConnection connection = car.result(); JsonArray data = new JsonArray().add(message.body().getString("id")); connection.updateWithParams(sqlQueries.get(SqlQuery.DELETE_PAGE), data, res -> { connection.close(); if (res.succeeded()) { message.reply(new JsonObject().put("result", "ok")); } else { reportQueryError(message, res.cause()); } }); } else { reportQueryError(message, car.cause()); } }); }

Slide 59

Slide 59 text

switch (message.headers().get("action")) { case "all-pages": fetchAllPages(message); break; case "get-page": fetchPage(message); break; case "create-page": createPage(message); break; case "save-page": savePage(message); break; case "delete-page": deletePage(message); break; default: message.fail(ErrorCodes.BAD_ACTION.ordinal(), "Bad action: " + action); } 7 If lots of actions…

Slide 60

Slide 60 text

@ProxyGen public interface WikiDatabaseService { // ( ...) @Fluent WikiDatabaseService savePage(int id, String markdown, Handler> resultHandler); @Fluent WikiDatabaseService deletePage(int id, Handler> resultHandler); static WikiDatabaseService createProxy(Vertx vertx, String address) { return new WikiDatabaseServiceVertxEBProxy(vertx, address); } // ( ...) } Proxy + handler source code will be generated Parameters from a JSON document Handlers for replies Generated proxy

Slide 61

Slide 61 text

dbService = WikiDatabaseService.createProxy(vertx, "wikidb.queue"); private void pageDeletionHandler(RoutingContext context) { dbService.deletePage(Integer.valueOf(context.request().getParam("id")), reply -> { if (reply.succeeded()) { context.response().setStatusCode(303); context.response().putHeader("Location", "/"); context.response().end(); } else { context.fail(reply.cause()); } }); }

Slide 62

Slide 62 text

?

Slide 63

Slide 63 text

(demo — failover)

Slide 64

Slide 64 text

Networking with Vert.x

Slide 65

Slide 65 text

Networking with Vert.x Vert.x Core TCP, HTTP/1, HTTP/2, WebSocket, UDP, DNS Vert.x Web SockJS MQTT Server

Slide 66

Slide 66 text

Networking with Vert.x SSL/TLS Native SSL Asynchronous DNS resolver Proxy socks4, socks5, HTTP connect Metrics

Slide 67

Slide 67 text

HTTP with Vert.x Server, client HTTP/1, HTTP/2 Websockets SockJS Persistent connections

Slide 68

Slide 68 text

Typical HTTP server MongoClient client = MongoClient.createNonShared(vertx, getConfig());
 HttpServer server = vertx.createHttpServer(); 
 server.requestHandler(request -> {
 if (request.path().equals("/document")) {
 client.findOne("docs", QUERY, fieldsOf(request), ar -> {
 if (ar.succeeded()) {
 String json = ar.result().encode();
 request.response().end(json);
 } else {
 request.response().setStatusCode(500).end();
 }
 });
 } else { /* … */ }
 });
 
 server.listen(8080);

Slide 69

Slide 69 text

Server concurrency Mongo EventLoop

Slide 70

Slide 70 text

HTTP service with an S3 backend HttpServer server = vertx.createHttpServer();
 S3Client s3Client = new S3Client();
 
 server.requestHandler(request -> {
 if (request.method() == PUT && request.path().equals("/upload")) {
 request.bodyHandler(data -> {
 s3Client.put("the-bucket", "the-key", data, s3Response -> {
 HttpServerResponse response = request.response();
 response
 .setStatusCode(s3Response.statusCode())
 .end();
 });
 });
 }
 });
 
 server.listen(8080);

Slide 71

Slide 71 text

Streaming to S3 server.requestHandler(request -> {
 if (request.method() == PUT && request.path().equals("/upload")) {
 
 S3ClientRequest s3Request = s3Client.createPutRequest(
 "the-bucket", "the-key", s3Response -> {
 HttpServerResponse response = request.response();
 response
 .setStatusCode(s3Response.statusCode())
 .end();
 });
 
 request.handler(chunk -> s3Request.write(chunk)); 
 request.endHandler(v -> s3Request.end());
 }
 });

Slide 72

Slide 72 text

request.handler(data -> {
 s3request.write(data);
 });


Slide 73

Slide 73 text

request.handler(data -> {
 s3request.write(data);
 });


Slide 74

Slide 74 text

request.handler(data -> {
 s3request.write(data);
 });


Slide 75

Slide 75 text

Transfering data fast reads slow writes

Slide 76

Slide 76 text

Back-pressure signal back-pressure propagates as a signal between systems in protocols network Inter Process communication pipes threads etc…

Slide 77

Slide 77 text

Back-pressure mechanism in protocols to slow down the data flow between a producer and a consumer when demand> capacity : queue or drop packets

Slide 78

Slide 78 text

Back-pressure in protocols TCP HTTP/2 Websockets / SockJS AMQP OS pipes etc…

Slide 79

Slide 79 text

ACK(8192) TCP writable read 8kb 8kb Back-pressure in TCP

Slide 80

Slide 80 text

8kb // Might block when the buffer is empty
 int n = request.getInputStream().read(data);
 
 // Got some bytes // Might block when the buffer is full
 s3request.getOutputStream().write(data, 0, n); // Queued for sending 8kb

Slide 81

Slide 81 text

request.handler(data -> {
 if (!s3request.writeQueueFull()) { s3request.write(data); } });
 full

Slide 82

Slide 82 text

request.handler(data -> {
 s3request.write(data); if (s3request.writeQueueFull()) { // stop reading from the request request.pause(); } });
 full pause

Slide 83

Slide 83 text

request.handler(data -> {
 s3request.write(data); if (s3request.writeQueueFull()) { request.pause(); s3request.drainHandler(v -> { socket.resume(); }); } });
 drain resume

Slide 84

Slide 84 text

Read stream public interface ReadStream {
 
 void pause();
 
 void resume();
 
 void handler(Handler handler);
 
 void endHandler(Handler handler);
 
 }

Slide 85

Slide 85 text

Write stream public interface WriteStream {
 
 void write(T data);
 
 boolean writeQueueFull();
 
 void drainHandler(Handler handler);
 
 void end();
 
 }

Slide 86

Slide 86 text

Pumping Pump pump = Pump.pump(request, s3request); pump.start();
 request.endHandler(v -> { pump.stop(); s3Request.end(); });


Slide 87

Slide 87 text

Unified back-pressure TCP streams HTTP client/server request/responses WebSocket Async file Kafka client consumer/producer SockJS OS pipes

Slide 88

Slide 88 text

Vert.x provides an unified model for dealing with back- pressured streams Reactive-stream for interoperability in Java ecosystem

Slide 89

Slide 89 text

Scaling servers

Slide 90

Slide 90 text

class Server extends AbstractVerticle {
 @Override
 public void start() throws Exception {
 HttpServer server = vertx.createHttpServer();
 server.requestHandler(req -> {
 req.response().end("Hello from");
 });
 server.listen(8080);
 }
 }
 
 // Will it bind ?
 vertx.deployVerticle(
 Server.class.getName(),
 new DeploymentOptions().setInstances(3)
 );

Slide 91

Slide 91 text

8 8 8

Slide 92

Slide 92 text

?

Slide 93

Slide 93 text

Boiler Vroom (wifi “Boiler Vroom”)

Slide 94

Slide 94 text

Boiler Vroom, unplugged

Slide 95

Slide 95 text

9 : ; < IceCast VLC Clients = OGG/Vorbis OGG/Vorbis MP3 MP3 HTTP 1.0 HTTP 1.1 HTTP Client Event bus → Chunked HTTP

Slide 96

Slide 96 text

9 : ; < IceCast VLC > Chrome / DJ Booth app Clients = NuProcess MIDI Event Bus Event Bus

Slide 97

Slide 97 text

MIDI Signals Channel control Note on / off Start / Stop Pitchbend Clock (…) https://github.com/cotejp/webmidi https://webaudio.github.io/web-midi-api/ https://github.com/jponge/webmidi-sequencer ? https://github.com/jponge/boiler-vroom 24 clock messages per bar

Slide 98

Slide 98 text

> 6 WebMidi JSON / Event Bus

Slide 99

Slide 99 text

MIDI In / Out mappings

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

(Code walkthrough)

Slide 102

Slide 102 text

Guest 1

Slide 103

Slide 103 text

About me ● Sébastien Blanc ● Red Hat, Keycloak team ● @sebi2706

Slide 104

Slide 104 text

The vertx TCP eventbus bridge ● Clients don’t need to be part of the cluster. ● Several clients available : Go, C++, Python, JS, JS (Browser and NodeJS) , Java ... ● Strict protocol but easy to implement : ○ 4bytes int32 message length (big endian encoding) ○ json string (encoded in UTF-8)

Slide 105

Slide 105 text

The vertx java TCP eventbus bridge Client ● Small library ● 0 dependency ● Language level >= 7 ● Simple API : EventBus eventBus = new EventBus("localhost",7000, new MessageHandler() { public void handle(Message message) { //Handle error } });

Slide 106

Slide 106 text

Register to an address eventBus.register("yourAddress", headers, new MessageHandler() { public void handle(Message responseMessage) { //handle response message; } }); Create a message Message message = new Message(); message.setAddress("yourAddress"); Map bodyMap = new LinkedHashMap(); bodyMap.put("action","forward"); message.setBody(bodyMap);

Slide 107

Slide 107 text

Publish to an Address eventBus.publishMessage(message); Send to an Address eventBus.sendMessage(message, new MessageHandler() { public void handle(Message responseMessage) { //handle response message; } });

Slide 108

Slide 108 text

Vert.x EventBus TCP Bridge verticle

Slide 109

Slide 109 text

Guest 2

Slide 110

Slide 110 text

@raphaelluta • Consultant Technique Indépendant Web & Data • Master 2 Commerce Electronique
 Université Paris Est Créteil • Membre
 Apache Software Foundation • Adepte de Pareto • Disciple de Little et Gunther • Speaker occasionnel

Slide 111

Slide 111 text

No content

Slide 112

Slide 112 text

Architecture HBase Kafka OpenTSDB Vert.x
 
 vertx-core vertx-web
 vertx-jdbc
 vertx-auth Spark Kafka API REST SSE

Slide 113

Slide 113 text

Pourquoi Vert.x ? • Réactif bien adapté pour le streaming • Développement de services indépendants, communiquant via l’event bus • …mais déploiement dans la même JVM possible

Slide 114

Slide 114 text

Guest 3

Slide 115

Slide 115 text

Vert-x, Polyglot + IOT?

Slide 116

Slide 116 text

Philippe Charrière aka @k33g_org • Previously: solution engineer @GitHub • raising source code • Currently: CSO & tech evangelist @Clever_Cloud • deploying apps like a God ⚡ • And especially, core committer on the well known Eclipse Golo project • 2 passions: • blinking leds (I ❤ IOT) & REST applications (with any languages) • I create a web framework every day (it’s a legend)

Slide 117

Slide 117 text

3 use cases • Blinking LEDs • Quick “microservices” • Playing with MQTT

Slide 118

Slide 118 text

1st use case • Blinking LEDs with RPI 0 • Using a dynamic language (for the JVM) • Editing code and compiling in ssh it's boring • “Running blink” from my browser

Slide 119

Slide 119 text

My weapons • Golo - Eclipse Foundation project • A dynamic language for the JVM build with invoke dynamic • Light (~700 kb) and fast (in a dynamic context) • PI4J - Java I/O Library for RPI • Vert-x • io.vertx.ext.web + io.vertx.core.http

Slide 120

Slide 120 text

The expected result

Slide 121

Slide 121 text

The expected result

Slide 122

Slide 122 text

Golo augment Vert-x augment io.vertx.ext.web.Router { function get = |this, uri, handler| { return this: get(uri): handler(handler) } function post = |this, uri, handler| { return this: post(uri): handler(handler) } } augment io.vertx.core.http.HttpServerRequest { function param = |this, paramName| -> this: getParam(paramName) } augment io.vertx.core.http.HttpServerResponse { function djson = |this| { this: putHeader("content-type", "application/json;charset=UTF-8") return DynamicObject(): define("send", |self| { this: end(JSON.stringify(self), "UTF-8") }) } }

Slide 123

Slide 123 text

Golo augment Vert-x let server = createHttpServer() let router = getRouter() router: get("/blink/:led", |context| { trying({ let selectedLed = context: request(): param("led") match { when selectedLed: equals(“red") then redWorker: send(5) when selectedLed: equals(“green") then greenWorker: send(5) when selectedLed: equals(“blue") then blueWorker: send(5) otherwise raise(" Huston!") } return selectedLed }) : either( recover = |error| -> context: response(): djson(): error(error: message()): send(), mapping = |selectedLed| -> context: response(): djson(): led(selectedLed): send() ) }) startHttpServer(server=server, router=router, port=9091, staticPath=" /*")

Slide 124

Slide 124 text

2nd use case • Simulate sensors gateways • Using a less dynamic and more typed language (for the JVM) to write some kind of “microservice” • POC for my current company

Slide 125

Slide 125 text

My weapons • Scala - ⚠ steps • In fact, Scala is simple as JavaScript, with a little effort • Vert.x • io.vertx.scala.ext.web + io.vertx.scala.core • ❤ vertx.setPeriodic

Slide 126

Slide 126 text

The expected result

Slide 127

Slide 127 text

vertx.setPeriodic is class Component(val min:Double, val max:Double) { var value:Double = 0.0 private val vertx = Vertx.vertx() private val getRandomInt = (min:Int, max:Int) => Math.floor(Math.random()*(max - min +1)) + min private val B = Math.PI / 2.0 private val unitsTranslatedToTheRight = getRandomInt(0, 5) private val amplitude = () => (this.max - this.min)/2.0 private val unitsTranslatedUp = () => this.min + amplitude() private val getLevel = (t: Double) => amplitude() * Math.cos(B*(t-unitsTranslatedToTheRight)) + unitsTranslatedUp() private val timer = vertx.setPeriodic(1000, (v) => { val now = LocalDateTime.now() val t:Double = now.getMinute + now.getSecond / 100.0 value = getLevel(t) }) def cancel() = { vertx.cancelTimer(timer) } }

Slide 128

Slide 128 text

io.vertx.scala.ext.web, it’s like Express.js val server = vertx.createHttpServer() val router = Router.router(vertx) val jsonStr = (obj: Any) => jsonMapper.writeValueAsString(obj) val temperatureSensorHome = new Temperature(14.0, 22.0) val temperatureSensorGarden = new Temperature(-10.0, 10.0) val humidityGreenHouse = new Humidity(0.0, 100.0) router.route("/temperature/home").handler(context => { context.response().end(jsonStr(temperatureSensorHome)) }) router.route("/temperature/garden").handler(context => { context.response().end(jsonStr(temperatureSensorGarden)) }) router.route("/humidity/greenhouse").handler(context => { context.response().end(jsonStr(humidityGreenHouse)) }) server.requestHandler(router.accept _).listen(8080)

Slide 129

Slide 129 text

3rd use case • Simulate sensors gateways • So, using Scala • and MQTT • POC for my current company

Slide 130

Slide 130 text

My weapons • Scala • Vert/x • io.vertx.scala.mqtt + io.vertx.scala.core + vertx.setPeriodic • Paho - Java version + MQTT.js • MQTT Clients

Slide 131

Slide 131 text

MQTT? Message Queue Telemetry Transport https://eclipse.org/community/eclipse_newsletter/2014/february/article2.php

Slide 132

Slide 132 text

The expected result Publishers MQTT Broker Subscriber Subscriber

Slide 133

Slide 133 text

The expected result

Slide 134

Slide 134 text

Some MQTT publisher(s) with Paho val sensorGreenHouse = new Humidity(0.0, 100.0) def getClient(id: String):MqttClient = { val brokerUrl = "tcp: //localhost:1883" val persistence = new MemoryPersistence val client = new MqttClient(brokerUrl, id, persistence) client.connect() client } vertx.setPeriodic(4000, (v) => { Try({ getClient("greenhouse") .getTopic("/humidity/greenhouse") .publish( new MqttMessage( s"${sensorGreenHouse.value} ${sensorGreenHouse.unit}”.getBytes(“utf-8") )) }) match { case Success(value) => println(s" Data published") case Failure(cause) => println(s" Huston? ${cause.getMessage}") } })

Slide 135

Slide 135 text

We need a MQTT broker! ⚠ Don’t use it in production mqttServer.endpointHandler(endpoint => { endpoint.accept(false) clientsMap(endpoint.clientIdentifier()) = endpoint // Add the endpoint to the clients map endpoint.subscribeHandler(subscribe => { // update subscriptions subscribe.topicSubscriptions.foreach(subscription => { subscriptionsMap(endpoint.clientIdentifier()+"-"+subscription.topicName()) = true }) }) endpoint.publishHandler(message => { // You've got a clientsMap.values.foreach((client) => { // if has subscribed to the current topic, then send subscriptionsMap.get(client.clientIdentifier()+"-"+message.topicName()) match { case Some(b) => client.publish(message.topicName(), Buffer.buffer(message.payload().toString()), MqttQoS.AT_LEAST_ONCE, false, false) case None => { /* */ } } }) }) }) mqttServer.listen()

Slide 136

Slide 136 text

Some MQTT subscribers(s) with MQTT.js var mqtt = require('mqtt') var client = mqtt.connect('mqtt: //localhost:1883') client.on('connect', () => { client.subscribe('/temperature/home') client.publish('/presence', 'yo mqtt server') }) client.on('message', (topic, message) => { console.log(message.toString()) })

Slide 137

Slide 137 text

(Reactive) Ecosystem

Slide 138

Slide 138 text

Databases • MySQL, PostgreSQL • JDBC • MongoDB • Redis

Slide 139

Slide 139 text

Authentication / Security • Auth: • Apache Shiro (LDAP, properties, …) • JDBC • MongoDB • OAuth (+ providers) • Json Web Tokens (JWT)

Slide 140

Slide 140 text

Metrics • DropWizard • Hawkular • Health Checks

Slide 141

Slide 141 text

Messaging / Integration • AMQP 1.0 • STOMP • SMTP • Kafka • RabbitMQ • Camel • JCA

Slide 142

Slide 142 text

Microservices • Discovery • Circuit breaker • Config • Consul • Kubernetes • GRPC

Slide 143

Slide 143 text

Clustering • Hazelcast • Apache Ignite • Infinispan • Apache Zookeeper

Slide 144

Slide 144 text

Last but not least… • vertx-unit • Because testing async code is a bit different… • Integrates with JUnit

Slide 145

Slide 145 text

Reactive Programming with Vert.x and RxJava

Slide 146

Slide 146 text

RxJava Data and events flows Great at organizing transformation of data and coordination of events It makes most sense when many sources of events are involved

Slide 147

Slide 147 text

Motivation Future> is not appropriate Dealing with latencies Functional programming influence

Slide 148

Slide 148 text

Push based subscribe ➊ ➋push Observer Observable

Slide 149

Slide 149 text

Iterable / Observable try {
 for (String item : it) { ➊
 } ➌
 } catch (Throwable e) { ➋
 } observable.subscribe(item -> {
 ➊ // onNext
 }, error -> {
 ➋ // onError
 }, () -> {
 ➌ // onCompleted
 });

Slide 150

Slide 150 text

0 1 0..n Reactive Completable Single Observable Interactive void T Iterable

Slide 151

Slide 151 text

Reactive pull back pressure subscribe ➊ ➌push Observer Observable ➋request

Slide 152

Slide 152 text

Operators

Slide 153

Slide 153 text

Rxified APIs Each API type (annotated with @VertxGen) has its prefix io.vertx replaced by io.vertx.rxjava io.vertx.core.Vertx @ io.vertx.rxjava.Vertx etc…

Slide 154

Slide 154 text

Rxified ReadStream package io.vertx.rxjava.core.streams; interface ReadStream {
 
 /**
 * @return an unicast and back-pressurable Observable,
 * hot or not depends on the stream
 */
 Observable toObservable();
 }

Slide 155

Slide 155 text

Rxified HttpServerRequest server.requestHandler(request -> {
 
 Observable obs = request.toObservable();
 
 obs.subscribe(buffer -> {
 // A new buffer
 }, err -> {
 // Something wrong happened
 }, () -> {
 // Done
 });
 });

Slide 156

Slide 156 text

Rxified Handler void listen(int port, Handler> ar)
 
 Single rxListen(int port);

Slide 157

Slide 157 text

server.rxListen(8080).subscribe(
 s -> {
 // Server started
 },
 err -> {
 // Could not start server
 }
 );

Slide 158

Slide 158 text

HttpRequest request = client.put(8080, "example.com", "/");
 
 Observable stream = getSomeObservable();
 
 // Create a single, the request is not yet sent
 Single> single = request.rxSendStream(stream);
 
 for (int i = 0;i < 5;i ++) {
 // Actually send the request and subscribe to the observable
 single.subscribe(response -> {
 // Handle the response
 }, error -> {
 // Handle the error
 });
 }

Slide 159

Slide 159 text

Composing singles Single> req1 = createRequest1();
 Single> req2 = createRequest2(); 
 Single single = Single.zip(
 req1.retry(3),
 req2,
 (buf1, buf2) ->
 new JsonObject().mergeIn(buf1.body()).mergeIn(buf2.body()));
 single.subscribe(json -> {
 // Got merged result
 }, err -> {
 // Got error
 });

Slide 160

Slide 160 text

Observable demo A B B B Kafka Topic MetricsVerticle(s) EventBus bridge Dashboard . Dashboard Verticle

Slide 161

Slide 161 text

RxJava 2 Better performances Based on reactive-streams Null values forbidden More reactive types Observable / Flowable Single / Maybe / Completable Prototype at https://github.com/vert-x3/vertx-rx

Slide 162

Slide 162 text

?

Slide 163

Slide 163 text

Outro

Slide 164

Slide 164 text

Vert.x stack

Slide 165

Slide 165 text

Vert.x Awesome Vert.x Stack Vert.x Core

Slide 166

Slide 166 text

That’s all folks Enjoy the benefits of Reactive with the Vert.x ecosystem Want more? C Microservices réactifs avec Eclipse Vert.x et Kubernetes vendredi 7 avril 14h55