Slide 1

Slide 1 text

#BSGTHEPLAN #BDXIO17 The Plan

Slide 2

Slide 2 text

#BSGTHEPLAN #BDXIO17 bonjour Philippe Charrière @clever_cloud ! @k33g_org G @k33g I ❤JavaScript, I Java, I JVM, I Scala (depuis peu…)

Slide 3

Slide 3 text

#BSGTHEPLAN #BDXIO17 Les origines de ce talk? Démos clients Monter en compétence sur les microservices (et vert.x) partager ce que j’ai appris (~ tuto) https://github.com/the-plan

Slide 4

Slide 4 text

#BSGTHEPLAN #BDXIO17 Microservices ???

Slide 5

Slide 5 text

#BSGTHEPLAN #BDXIO17 –Philippe Charrière “Les microservices sont des morceaux d’application(s) développés de manière indépendante, déployés de manière indépendante et gérés par de petites équipes ” “Un microservice est petit, car il résout un seul problème”

Slide 6

Slide 6 text

#BSGTHEPLAN #BDXIO17 Les qualités d’un microservice ?

Slide 7

Slide 7 text

#BSGTHEPLAN #BDXIO17 Les qualités d’un microservice ? Avoir un seul objectif Encapsulation Appropriation par l’équipe Autonomie de l’équipe Versions multiples Chorégraphie Eventual consistency (cohérence à terme)

Slide 8

Slide 8 text

#BSGTHEPLAN #BDXIO17 Les qualités d’un microservice ? Avoir un seul objectif Encapsulation Appropriation par l’équipe Autonomie de l’équipe Versions multiples Chorégraphie Eventual consistency (cohérence à terme)

Slide 9

Slide 9 text

#BSGTHEPLAN #BDXIO17 Les qualités d’un microservice ? Avoir un seul objectif Encapsulation Appropriation par l’équipe Autonomie de l’équipe Versions multiples Chorégraphie Eventual consistency (cohérence à terme)

Slide 10

Slide 10 text

#BSGTHEPLAN #BDXIO17 Les qualités d’un microservice ? Avoir un seul objectif Encapsulation Appropriation par l’équipe Autonomie de l’équipe Versions multiples Chorégraphie Eventual consistency (cohérence à terme)

Slide 11

Slide 11 text

#BSGTHEPLAN #BDXIO17 Les qualités d’un microservice ? Avoir un seul objectif Encapsulation Appropriation par l’équipe Autonomie de l’équipe Versions multiples Chorégraphie Eventual consistency (cohérence à terme)

Slide 12

Slide 12 text

#BSGTHEPLAN #BDXIO17 Les qualités d’un microservice ? Avoir un seul objectif Encapsulation Appropriation par l’équipe Autonomie de l’équipe Versions multiples Chorégraphie Eventual consistency (cohérence à terme)

Slide 13

Slide 13 text

#BSGTHEPLAN #BDXIO17 Les qualités d’un microservice ? Avoir un seul objectif Encapsulation Appropriation par l’équipe Autonomie de l’équipe Versions multiples Chorégraphie Eventual consistency (cohérence à terme)

Slide 14

Slide 14 text

#BSGTHEPLAN #BDXIO17 Pourquoi c’est bien ? … les microservices

Slide 15

Slide 15 text

#BSGTHEPLAN #BDXIO17 Pourquoi c’est bien ? Time to Market plus rapide Code moins compliqué et meilleur Responsabilité Des niveaux d’expertise élevés par équipe Externalisation plus facile Securité

Slide 16

Slide 16 text

#BSGTHEPLAN #BDXIO17 Pourquoi c’est bien ? Time to Market plus rapide Code moins compliqué et meilleur Responsabilité Des niveaux d’expertise élevés par équipe Externalisation plus facile Securité

Slide 17

Slide 17 text

#BSGTHEPLAN #BDXIO17 Pourquoi c’est bien ? Time to Market plus rapide Code moins compliqué et meilleur Responsabilité Des niveaux d’expertise élevés par équipe Externalisation plus facile Securité

Slide 18

Slide 18 text

#BSGTHEPLAN #BDXIO17 Pourquoi c’est bien ? Time to Market plus rapide Code moins compliqué et meilleur Responsabilité Des niveaux d’expertises élevés par équipe Externalisation plus facile Securité

Slide 19

Slide 19 text

#BSGTHEPLAN #BDXIO17 Pourquoi c’est bien ? Time to Market plus rapide Code moins compliqué et meilleur Responsabilité Des niveaux d’expertises élevés par équipe Externalisation plus facile Securité

Slide 20

Slide 20 text

#BSGTHEPLAN #BDXIO17 Pourquoi c’est bien ? Time to Market plus rapide Code moins compliqué et meilleur Responsabilité Des niveaux d’expertises élevés par équipe Externalisation plus facile Sécurité

Slide 21

Slide 21 text

#BSGTHEPLAN #BDXIO17 Pourquoi ce n’est pas toujours simple ? … les microservices

Slide 22

Slide 22 text

#BSGTHEPLAN #BDXIO17 Pourquoi ce n’est pas toujours simple ? Complexité externe Maturité “organisationnelle” Duplication (multiplication) Eventual consistency (cohérence à terme) Testing, simple … ou pas Monitoring

Slide 23

Slide 23 text

#BSGTHEPLAN #BDXIO17 Pourquoi ce n’est pas toujours simple ? Complexité externe Maturité “organisationnelle” Duplication (multiplication) Eventual consistency (cohérence à terme) Testing, simple … ou pas Monitoring

Slide 24

Slide 24 text

#BSGTHEPLAN #BDXIO17 Pourquoi ce n’est pas toujours simple ? Complexité externe Maturité “organisationnelle” Duplication (multiplication) Eventual consistency (cohérence à terme) Testing, simple … ou pas Monitoring

Slide 25

Slide 25 text

#BSGTHEPLAN #BDXIO17 Pourquoi ce n’est pas toujours simple ? Complexité externe Maturité “organisationnelle” Duplication (multiplication) Eventual consistency (cohérence à terme) Testing, simple … ou pas Monitoring

Slide 26

Slide 26 text

#BSGTHEPLAN #BDXIO17 Pourquoi ce n’est pas toujours simple ? Complexité externe Maturité “organisationnelle” Duplication (multiplication) Eventual consistency (cohérence à terme) Testing, simple … ou pas Monitoring

Slide 27

Slide 27 text

#BSGTHEPLAN #BDXIO17 Pourquoi ce n’est pas toujours simple ? Complexité externe Maturité “organisationnelle” Duplication (multiplication) Eventual consistency (cohérence à terme) Testing, simple … ou pas Monitoring

Slide 28

Slide 28 text

#BSGTHEPLAN #BDXIO17 VERT.X Projet RedHat #BSGTHEPLAN #BDXIO17

Slide 29

Slide 29 text

#BSGTHEPLAN #BDXIO17 Pourquoi Vert.x Pas besoin de serveur d’application, de servlet Simple (à utiliser, à coder, à builder, à déployer) Polyglotte Comme à la maison, on dirait du #JavaScript Asynchrone Une dream team

Slide 30

Slide 30 text

#BSGTHEPLAN #BDXIO17 microservices Vert.x En ce qui concerne la partie Microservices Agnostique sur la partie Discovery Léger Des composants pour une architecture stable & résilience: Health Checks Circuit Breakers …

Slide 31

Slide 31 text

#BSGTHEPLAN #BDXIO17 microservices Vert.x

Slide 32

Slide 32 text

#BSGTHEPLAN #BDXIO17 Une intro à Vert.x http://vertx.io/docs/guide-for-java-devs/

Slide 33

Slide 33 text

#BSGTHEPLAN #BDXIO17 #BSGTHEPLAN #BDXIO17

Slide 34

Slide 34 text

#BSGTHEPLAN #BDXIO17 1 microservice REST Vert.x public class BaseStar extends AbstractVerticle { public void start() { Router router = Router.router(vertx); router.route().handler(BodyHandler.create()); router.get("/api/hello").handler(context -> { context.response() .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonObject().put("message", "hello").encodePrettily()); }); Integer httpPort = 8080; HttpServer server = vertx.createHttpServer(); server.requestHandler(router::accept).listen(httpPort, result -> { System.out.println(" Listening on " + httpPort); }); } }

Slide 35

Slide 35 text

#BSGTHEPLAN #BDXIO17 micro, m’ouais … Distribuer les fonctionnalités et les données Identifier les microservices, les trouver, … Gérer la cohérence et la fiabilité du réseau pour chacun Composants distribués + Technologies différentes = “new modes of failure” Quand ça ne marche pas … Complexité d’investigation

Slide 36

Slide 36 text

#BSGTHEPLAN #BDXIO17 Le Plan Redis + http

Slide 37

Slide 37 text

#BSGTHEPLAN #BDXIO17 objectifs #BSGTHEPLAN #BDXIO17

Slide 38

Slide 38 text

#BSGTHEPLAN #BDXIO17 Plan de “the plan” BaseStars WebApp Raiders Conclusion(s)

Slide 39

Slide 39 text

#BSGTHEPLAN #BDXIO17 BaseStar Java

Slide 40

Slide 40 text

#BSGTHEPLAN #BDXIO17 BaseStar Service Discovery & Backend

Slide 41

Slide 41 text

#BSGTHEPLAN #BDXIO17 s’enregistrer BaseStar JAVA BaseStar JAVA BaseStar JAVA BaseStar JAVA REDIS BaseStar JAVA

Slide 42

Slide 42 text

#BSGTHEPLAN #BDXIO17 s’enregistrer - ServiceDiscovery public class BaseStar extends AbstractVerticle { public void start() { // Discovery settings ServiceDiscoveryOptions serviceDiscoveryOptions = new ServiceDiscoveryOptions(); // Redis settings with the standard Redis Backend Integer redisPort = Integer.parseInt(Optional.ofNullable(System.getenv("REDIS_PORT")).orElse("6379")); String redisHost = Optional.ofNullable(System.getenv("REDIS_HOST")).orElse("127.0.0.1"); String redisAuth = Optional.ofNullable(System.getenv("REDIS_PASSWORD")).orElse(null); String redisRecordsKey = Optional.ofNullable(System.getenv("REDIS_RECORDS_KEY")).orElse("vert.x.ms"); discovery = ServiceDiscovery.create( vertx, serviceDiscoveryOptions.setBackendConfiguration( new JsonObject() .put("host", redisHost) .put("port", redisPort) .put("auth", redisAuth) .put("key", redisRecordsKey) )); } }

Slide 43

Slide 43 text

#BSGTHEPLAN #BDXIO17 s’enregistrer - ServiceDiscovery public class BaseStar extends AbstractVerticle { public void start() { // Discovery settings ServiceDiscoveryOptions serviceDiscoveryOptions = new ServiceDiscoveryOptions(); // Redis settings with the standard Redis Backend Integer redisPort = Integer.parseInt(Optional.ofNullable(System.getenv("REDIS_PORT")).orElse("6379")); String redisHost = Optional.ofNullable(System.getenv("REDIS_HOST")).orElse("127.0.0.1"); String redisAuth = Optional.ofNullable(System.getenv("REDIS_PASSWORD")).orElse(null); String redisRecordsKey = Optional.ofNullable(System.getenv("REDIS_RECORDS_KEY")).orElse("vert.x.ms"); discovery = ServiceDiscovery.create( vertx, serviceDiscoveryOptions.setBackendConfiguration( new JsonObject() .put("host", redisHost) .put("port", redisPort) .put("auth", redisAuth) .put("key", redisRecordsKey) )); } }

Slide 44

Slide 44 text

#BSGTHEPLAN #BDXIO17 s’enregistrer - Record public class BaseStar extends AbstractVerticle { public void start() { // microservice options Haikunator haikunator = new HaikunatorBuilder().setTokenLength(6).build(); String niceName = haikunator.haikunate(); String serviceName = Optional.ofNullable(System.getenv("SERVICE_NAME")).orElse("the-plan")+"-"+niceName; String serviceHost = Optional.ofNullable(System.getenv("SERVICE_HOST")).orElse("localhost"); Integer servicePort = Integer.parseInt(Optional.ofNullable(System.getenv("SERVICE_PORT")).orElse("80")); String serviceRoot = Optional.ofNullable(System.getenv("SERVICE_ROOT")).orElse("/api"); String color = Optional.ofNullable(System.getenv("COLOR")).orElse("FFD433"); // create the microservice record record = HttpEndpoint.createRecord( serviceName, serviceHost, servicePort, serviceRoot ); } }

Slide 45

Slide 45 text

#BSGTHEPLAN #BDXIO17 s’enregistrer - MetaData public class BaseStar extends AbstractVerticle { public void start() { // add some metadata record.setMetadata(new JsonObject() .put("kind", "basestar") .put("message", "Hello ") .put("uri", "/coordinates") .put("raiders_counter", raidersCounter) .put("color", color) .put("app_id", Optional.ofNullable(System.getenv("APP_ID")).orElse("")) .put("instance_id", Optional.ofNullable(System.getenv("INSTANCE_ID")).orElse("")) .put("instance_type", Optional.ofNullable(System.getenv("INSTANCE_TYPE")).orElse("production")) .put("instance_number", Integer.parseInt(Optional.ofNullable(System.getenv("INSTANCE_NUMBER")).orElse("0"))) ); } }

Slide 46

Slide 46 text

#BSGTHEPLAN #BDXIO17 s’enregistrer & démarrer public class BaseStar extends AbstractVerticle { public void start() { Integer httpPort = Integer.parseInt(Optional.ofNullable(System.getenv("PORT")).orElse("8080")); HttpServer server = vertx.createHttpServer(); server.requestHandler(router::accept).listen(httpPort, result -> { if(result.succeeded()) { System.out.println(" Listening on " + httpPort); //publish the microservice to the discovery backend discovery.publish(record, asyncResult -> { if(asyncResult.succeeded()) { System.out.println("" + record.getRegistration()); } else { System.out.println("" + asyncResult.cause().getMessage()); } }); } else { System.out.println(" Houston, we have a problem: " + result.cause().getMessage()); } }); } }

Slide 47

Slide 47 text

#BSGTHEPLAN #BDXIO17 s’enregistrer & démarrer public class BaseStar extends AbstractVerticle { public void start() { Integer httpPort = Integer.parseInt(Optional.ofNullable(System.getenv("PORT")).orElse("8080")); HttpServer server = vertx.createHttpServer(); server.requestHandler(router::accept).listen(httpPort, result -> { if(result.succeeded()) { System.out.println(" Listening on " + httpPort); //publish the microservice to the discovery backend discovery.publish(record, asyncResult -> { if(asyncResult.succeeded()) { System.out.println("" + record.getRegistration()); } else { System.out.println("" + asyncResult.cause().getMessage()); } }); } else { System.out.println(" Houston, we have a problem: " + result.cause().getMessage()); } }); } }

Slide 48

Slide 48 text

#BSGTHEPLAN #BDXIO17 BaseStar Routes | Router

Slide 49

Slide 49 text

#BSGTHEPLAN #BDXIO17 Routes | Router public class BaseStar extends AbstractVerticle { public void start() { Router router = Router.router(vertx); router.route().handler(BodyHandler.create()); router.get("/api/raiders").handler(context -> { discovery.getRecords(r -> r.getMetadata().getString("kind").equals("raider") , ar -> { if (ar.succeeded()) { context.response() .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonArray(ar.result()).encodePrettily()); } }); }); // serve static assets, see /resources/webroot directory router.route("/*").handler(StaticHandler.create()); Integer httpPort = Integer.parseInt(Optional.ofNullable(System.getenv("PORT")).orElse("8080")); HttpServer server = vertx.createHttpServer(); server.requestHandler(router::accept).listen(httpPort, result -> { }); } }

Slide 50

Slide 50 text

#BSGTHEPLAN #BDXIO17 GET | /api/raiders public class BaseStar extends AbstractVerticle { public void start() { Router router = Router.router(vertx); router.route().handler(BodyHandler.create()); router.get("/api/raiders").handler(context -> { discovery.getRecords(r -> r.getMetadata().getString("kind").equals("raider") , ar -> { if (ar.succeeded()) { context.response() .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonArray(ar.result()).encodePrettily()); } }); }); // serve static assets, see /resources/webroot directory router.route("/*").handler(StaticHandler.create()); Integer httpPort = Integer.parseInt(Optional.ofNullable(System.getenv("PORT")).orElse("8080")); HttpServer server = vertx.createHttpServer(); server.requestHandler(router::accept).listen(httpPort, result -> { }); } }

Slide 51

Slide 51 text

#BSGTHEPLAN #BDXIO17 Permettre aux raiders de “s’enregistrer”

Slide 52

Slide 52 text

#BSGTHEPLAN #BDXIO17 POST | /api/raiders public class BaseStar extends AbstractVerticle { public void start() { router.post("/api/raiders").handler(context -> { // I'm a new raider String registationId = Optional.ofNullable(context.getBodyAsJson().getString("registration")).orElse("unknown"); discovery.getRecord(r -> r.getRegistration().equals(registationId), asyncResRecord -> { // = raider's record if(asyncResRecord.succeeded()) { Record raiderRecord = asyncResRecord.result(); ServiceReference reference = discovery.getReference(raiderRecord); WebClient raiderClient = reference.getAs(WebClient.class); // ⚠ get a web client this.raidersCounter += 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, ar -> { }); this.raiderWorker(raiderRecord,raiderClient); // this is a worker context.response() // ✉ message to the raider .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonObject().put("message", "ok, registered").encodePrettily()); } }); }); } }

Slide 53

Slide 53 text

#BSGTHEPLAN #BDXIO17 POST | /api/raiders public class BaseStar extends AbstractVerticle { public void start() { router.post("/api/raiders").handler(context -> { // I'm a new raider String registationId = Optional.ofNullable(context.getBodyAsJson().getString("registration")).orElse("unknown"); discovery.getRecord(r -> r.getRegistration().equals(registationId), asyncResRecord -> { // = raider's record if(asyncResRecord.succeeded()) { Record raiderRecord = asyncResRecord.result(); ServiceReference reference = discovery.getReference(raiderRecord); WebClient raiderClient = reference.getAs(WebClient.class); // ⚠ get a web client this.raidersCounter += 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, ar -> { }); this.raiderWorker(raiderRecord,raiderClient); // this is a worker context.response() // ✉ message to the raider .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonObject().put("message", "ok, registered").encodePrettily()); } }); }); } }

Slide 54

Slide 54 text

#BSGTHEPLAN #BDXIO17 POST | /api/raiders public class BaseStar extends AbstractVerticle { public void start() { router.post("/api/raiders").handler(context -> { // I'm a new raider String registationId = Optional.ofNullable(context.getBodyAsJson().getString("registration")).orElse("unknown"); discovery.getRecord(r -> r.getRegistration().equals(registationId), asyncResRecord -> { // = raider's record if(asyncResRecord.succeeded()) { Record raiderRecord = asyncResRecord.result(); ServiceReference reference = discovery.getReference(raiderRecord); WebClient raiderClient = reference.getAs(WebClient.class); // ⚠ get a web client this.raidersCounter += 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, ar -> { }); this.raiderWorker(raiderRecord,raiderClient); // this is a worker context.response() // ✉ message to the raider .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonObject().put("message", "ok, registered").encodePrettily()); } }); }); } }

Slide 55

Slide 55 text

#BSGTHEPLAN #BDXIO17 POST | /api/raiders public class BaseStar extends AbstractVerticle { public void start() { router.post("/api/raiders").handler(context -> { // I'm a new raider String registationId = Optional.ofNullable(context.getBodyAsJson().getString("registration")).orElse("unknown"); discovery.getRecord(r -> r.getRegistration().equals(registationId), asyncResRecord -> { // = raider's record if(asyncResRecord.succeeded()) { Record raiderRecord = asyncResRecord.result(); ServiceReference reference = discovery.getReference(raiderRecord); WebClient raiderClient = reference.getAs(WebClient.class); // ⚠ get a web client this.raidersCounter += 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, ar -> { }); this.raiderWorker(raiderRecord,raiderClient); // this is a worker context.response() // ✉ message to the raider .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonObject().put("message", "ok, registered").encodePrettily()); } }); }); } }

Slide 56

Slide 56 text

#BSGTHEPLAN #BDXIO17 POST | /api/raiders public class BaseStar extends AbstractVerticle { public void start() { router.post("/api/raiders").handler(context -> { // I'm a new raider String registationId = Optional.ofNullable(context.getBodyAsJson().getString("registration")).orElse("unknown"); discovery.getRecord(r -> r.getRegistration().equals(registationId), asyncResRecord -> { // = raider's record if(asyncResRecord.succeeded()) { Record raiderRecord = asyncResRecord.result(); ServiceReference reference = discovery.getReference(raiderRecord); WebClient raiderClient = reference.getAs(WebClient.class); // ⚠ get a web client this.raidersCounter += 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, ar -> { }); this.raiderWorker(raiderRecord,raiderClient); // this is a worker context.response() // ✉ message to the raider .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonObject().put("message", "ok, registered").encodePrettily()); } }); }); } }

Slide 57

Slide 57 text

#BSGTHEPLAN #BDXIO17 BaseStar HealthCheck ❤ Hey, toujours là ?

Slide 58

Slide 58 text

#BSGTHEPLAN #BDXIO17 HealthCheck ❤ public class BaseStar extends AbstractVerticle { public void start() { // health check of existing basestars HealthCheckHandler hch = HealthCheckHandler.create(vertx); hch.register("iamok", future -> discovery.getRecord(r -> r.getRegistration().equals(record.getRegistration()), ar -> { if(ar.succeeded()) { future.complete(); } else { // future.fail(ar.cause()); } }) ); router.get("/health").handler(hch); } }

Slide 59

Slide 59 text

#BSGTHEPLAN #BDXIO17 HealthCheck ❤ public class BaseStar extends AbstractVerticle { public void start() { // health check of existing basestars HealthCheckHandler hch = HealthCheckHandler.create(vertx); hch.register("iamok", future -> discovery.getRecord(r -> r.getRegistration().equals(record.getRegistration()), ar -> { if(ar.succeeded()) { future.complete(); } else { // future.fail(ar.cause()); } }) ); router.get("/health").handler(hch); } }

Slide 60

Slide 60 text

#BSGTHEPLAN #BDXIO17 HealthCheck ❤ public class BaseStar extends AbstractVerticle { public void start() { // health check of existing basestars HealthCheckHandler hch = HealthCheckHandler.create(vertx); hch.register("iamok", future -> discovery.getRecord(r -> r.getRegistration().equals(record.getRegistration()), ar -> { if(ar.succeeded()) { future.complete(); } else { // future.fail(ar.cause()); } }) ); router.get("/health").handler(hch); } }

Slide 61

Slide 61 text

#BSGTHEPLAN #BDXIO17 BaseStar Worker this.raiderWorker(raiderRecord,raiderClient); // this is a worker router.post("/api/raiders").handler(context -> { // I'm a new raider

Slide 62

Slide 62 text

#BSGTHEPLAN #BDXIO17 Worker private void raiderWorker(Record raiderRecord, WebClient raiderClient) { Raider thatRaider = new Raider( raiderRecord.getRegistration(), raiderRecord.getName(), raiderRecord.getMetadata().getJsonObject("coordinates").getDouble("x"), raiderRecord.getMetadata().getJsonObject("coordinates").getDouble("y"), new Constraints(5.0, 600.0, 600.0, 5.0) ); //… }

Slide 63

Slide 63 text

#BSGTHEPLAN #BDXIO17 Worker private void raiderWorker(Record raiderRecord, WebClient raiderClient) { //… vertx.setPeriodic(1000, timerID -> { // this is a worker // get the raiders list discovery.getRecords(r -> r.getMetadata().getString("kind").equals("raider") , ar -> { if(ar.succeeded()) { List raidersRecords = ar.result(); thatRaider.moveWith(raidersRecords, 300.0); thatRaider.moveCloser(raidersRecords, 300.0); thatRaider.moveAway(raidersRecords, 15.0); thatRaider.move(); // === try to contact the raider and post coordinates === raiderClient.post("/api/coordinates").sendJsonObject( new JsonObject() .put("x",thatRaider.x) .put("y",thatRaider.y) .put("xVelocity",thatRaider.xVelocity) .put("yVelocity",thatRaider.yVelocity), asyncPostRes -> { if(asyncPostRes.succeeded()) { System.out.println(" " + asyncPostRes.result().bodyAsJsonObject().encodePrettily()); } else { // ouch raidersCounter -= 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, asyncRecUpdateRes -> { vertx.cancelTimer(timerID);}); } } ); }); }); }

Slide 64

Slide 64 text

#BSGTHEPLAN #BDXIO17 Worker private void raiderWorker(Record raiderRecord, WebClient raiderClient) { //… vertx.setPeriodic(1000, timerID -> { // this is a worker // get the raiders list discovery.getRecords(r -> r.getMetadata().getString("kind").equals("raider") , ar -> { if(ar.succeeded()) { List raidersRecords = ar.result(); thatRaider.moveWith(raidersRecords, 300.0); thatRaider.moveCloser(raidersRecords, 300.0); thatRaider.moveAway(raidersRecords, 15.0); thatRaider.move(); // === try to contact the raider and post coordinates === raiderClient.post("/api/coordinates").sendJsonObject( new JsonObject() .put("x",thatRaider.x) .put("y",thatRaider.y) .put("xVelocity",thatRaider.xVelocity) .put("yVelocity",thatRaider.yVelocity), asyncPostRes -> { if(asyncPostRes.succeeded()) { System.out.println(" " + asyncPostRes.result().bodyAsJsonObject().encodePrettily()); } else { // ouch raidersCounter -= 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, asyncRecUpdateRes -> { vertx.cancelTimer(timerID);}); } } ); }); }); }

Slide 65

Slide 65 text

#BSGTHEPLAN #BDXIO17 Worker private void raiderWorker(Record raiderRecord, WebClient raiderClient) { //… vertx.setPeriodic(1000, timerID -> { // this is a worker // get the raiders list discovery.getRecords(r -> r.getMetadata().getString("kind").equals("raider") , ar -> { if(ar.succeeded()) { List raidersRecords = ar.result(); thatRaider.moveWith(raidersRecords, 300.0); thatRaider.moveCloser(raidersRecords, 300.0); thatRaider.moveAway(raidersRecords, 15.0); thatRaider.move(); // === try to contact the raider and post coordinates === raiderClient.post("/api/coordinates").sendJsonObject( new JsonObject() .put("x",thatRaider.x) .put("y",thatRaider.y) .put("xVelocity",thatRaider.xVelocity) .put("yVelocity",thatRaider.yVelocity), asyncPostRes -> { if(asyncPostRes.succeeded()) { System.out.println(" " + asyncPostRes.result().bodyAsJsonObject().encodePrettily()); } else { // ouch raidersCounter -= 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, asyncRecUpdateRes -> { vertx.cancelTimer(timerID);}); } } ); }); }); }

Slide 66

Slide 66 text

#BSGTHEPLAN #BDXIO17 Worker private void raiderWorker(Record raiderRecord, WebClient raiderClient) { //… vertx.setPeriodic(1000, timerID -> { // this is a worker // get the raiders list discovery.getRecords(r -> r.getMetadata().getString("kind").equals("raider") , ar -> { if(ar.succeeded()) { List raidersRecords = ar.result(); thatRaider.moveWith(raidersRecords, 300.0); thatRaider.moveCloser(raidersRecords, 300.0); thatRaider.moveAway(raidersRecords, 15.0); thatRaider.move(); // === try to contact the raider and post coordinates === raiderClient.post("/api/coordinates").sendJsonObject( new JsonObject() .put("x",thatRaider.x) .put("y",thatRaider.y) .put("xVelocity",thatRaider.xVelocity) .put("yVelocity",thatRaider.yVelocity), asyncPostRes -> { if(asyncPostRes.succeeded()) { System.out.println(" " + asyncPostRes.result().bodyAsJsonObject().encodePrettily()); } else { // ouch raidersCounter -= 1; record.getMetadata().put("raiders_counter", raidersCounter); discovery.update(record, asyncRecUpdateRes -> { vertx.cancelTimer(timerID);}); } } ); }); }); }

Slide 67

Slide 67 text

#BSGTHEPLAN #BDXIO17 Récapitulatif BaseStar JAVA BaseStar JAVA BaseStar JAVA BaseStar JAVA REDIS BaseStar JAVA GET http://localhost:808N/api/raiders POST http://localhost:808N/api/raiders GET http://localhost:808N/health Raider KOTLIN Raider KOTLIN Raider GROOVY Raider GROOVY POST http://localhost:909N/api/coordinates Hey pilotage

Slide 68

Slide 68 text

#BSGTHEPLAN #BDXIO17 checklist ✅ Démarrer les BaseStars ✅ cf Base Redis - MEDIS & health ✅ Démarrer Redis

Slide 69

Slide 69 text

#BSGTHEPLAN #BDXIO17 WebApp Scala + JavaScript

Slide 70

Slide 70 text

#BSGTHEPLAN #BDXIO17 WebApp BaseStar JAVA BaseStar JAVA BaseStar JAVA REDIS BaseStar JAVA GET http://localhost:808N/api/raiders POST http://localhost:808N/api/raiders GET http://localhost:808N/health BSG monitor SCALA GET http://localhost:8080/api/raiders BSG map JS http://localhost:7070 BaseStar JAVA Raider KOTLIN Raider KOTLIN Raider GROOVY Raider GROOVY POST http://localhost:909N/api/coordinates

Slide 71

Slide 71 text

#BSGTHEPLAN #BDXIO17 WebApp | Backend Scala val httpPort = sys.env.getOrElse("PORT", "8080").toInt router.get("/api/raiders").handler(context => { discovery .getRecordsFuture(record => record.getMetadata.getString("kind").equals("raider")) .onComplete { case Success(results) => { context .response() .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonArray(results.toList.asJava).encodePrettily()) } case Failure(cause) => { context .response() .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonObject().put("error", cause.getMessage).encodePrettily()) } } }) router.route("/*").handler(StaticHandler.create()) println(s" Listening on $httpPort - Enjoy ") server.requestHandler(router.accept _).listen(httpPort)

Slide 72

Slide 72 text

#BSGTHEPLAN #BDXIO17 WebApp | Backend Scala val httpPort = sys.env.getOrElse("PORT", "8080").toInt router.get("/api/raiders").handler(context => { discovery .getRecordsFuture(record => record.getMetadata.getString("kind").equals("raider")) .onComplete { case Success(results) => { context .response() .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonArray(results.toList.asJava).encodePrettily()) } case Failure(cause) => { context .response() .putHeader("content-type", "application/json;charset=UTF-8") .end(new JsonObject().put("error", cause.getMessage).encodePrettily()) } } }) router.route("/*").handler(StaticHandler.create()) println(s" Listening on $httpPort - Enjoy ") server.requestHandler(router.accept _).listen(httpPort)

Slide 73

Slide 73 text

#BSGTHEPLAN #BDXIO17 checklist ✅ Démarrer les BaseStars ✅ cf Base Redis - MEDIS ✅ Démarrer Redis ✅ Démarrer BSG Monitor ✅ Démarrer BSG Map

Slide 74

Slide 74 text

#BSGTHEPLAN #BDXIO17 Raider(s)

Slide 75

Slide 75 text

#BSGTHEPLAN #BDXIO17 Raider(s) BaseStar JAVA BaseStar JAVA BaseStar JAVA REDIS BaseStar JAVA GET http://localhost:808N/api/raiders POST http://localhost:808N/api/raiders GET http://localhost:808N/health BSG monitor SCALA GET http://localhost:8080/api/raiders BSG map JS http://localhost:7070 BaseStar JAVA Raider KOTLIN Raider KOTLIN Raider GROOVY Raider GROOVY POST http://localhost:909N/api/coordinates Raider GROOVY Raider KOTLIN Raider GROOVY

Slide 76

Slide 76 text

#BSGTHEPLAN #BDXIO17 Raider(s) | main + stop kotlin

Slide 77

Slide 77 text

#BSGTHEPLAN #BDXIO17 Raider(s) | main + stop fun main(args: Array) { val vertx = Vertx.vertx() vertx.deployVerticle(Raider()) } class Raider : AbstractVerticle() { override fun stop(stopFuture: Future) { super.stop() println("Unregistration process is started (${record?.registration})...") discovery?.unpublish(record?.registration, { ar -> when { ar.failed() -> { println(" Unable to unpublish the microservice: ${ar.cause().message}") stopFuture.fail(ar.cause()) } ar.succeeded() -> { println(" bye bye ${record?.registration}") stopFuture.complete() } } }) } override fun start() { … } }

Slide 78

Slide 78 text

#BSGTHEPLAN #BDXIO17 Raider(s) | main + stop fun main(args: Array) { val vertx = Vertx.vertx() vertx.deployVerticle(Raider()) } class Raider : AbstractVerticle() { override fun stop(stopFuture: Future) { super.stop() println("Unregistration process is started (${record?.registration})...") discovery?.unpublish(record?.registration, { ar -> when { ar.failed() -> { println(" Unable to unpublish the microservice: ${ar.cause().message}") stopFuture.fail(ar.cause()) } ar.succeeded() -> { println(" bye bye ${record?.registration}") stopFuture.complete() } } }) } override fun start() { … } }

Slide 79

Slide 79 text

#BSGTHEPLAN #BDXIO17 Raider(s) | start / discovery kotlin

Slide 80

Slide 80 text

#BSGTHEPLAN #BDXIO17 Raider(s) | s’enregistrer / ServiceDiscovery class Raider : AbstractVerticle() { override fun start() { /* === Discovery part === */ val redisPort= System.getenv("REDIS_PORT")?.toInt() ?: 6379 val redisHost = System.getenv("REDIS_HOST") ?: "127.0.0.1" val redisAuth = System.getenv("REDIS_PASSWORD") ?: null val redisRecordsKey = System.getenv("REDIS_RECORDS_KEY") ?: "vert.x.ms" val serviceDiscoveryOptions = ServiceDiscoveryOptions() discovery = ServiceDiscovery.create(vertx, serviceDiscoveryOptions.setBackendConfiguration( json { obj( "host" to redisHost, "port" to redisPort, "auth" to redisAuth, "key" to redisRecordsKey ) } )) } }

Slide 81

Slide 81 text

#BSGTHEPLAN #BDXIO17 Raider(s) | s’enregistrer / Record class Raider : AbstractVerticle() { override fun start() { // microservice informations val haikunator = HaikunatorBuilder().setTokenLength(3).build() val niceName = haikunator.haikunate() val serviceName = "${System.getenv("SERVICE_NAME") ?: "the-plan"}-$niceName" val serviceHost = System.getenv("SERVICE_HOST") ?: "localhost" val servicePort = System.getenv("SERVICE_PORT")?.toInt() ?: 80 val serviceRoot = System.getenv("SERVICE_ROOT") ?: "/api" // create the microservice record record = HttpEndpoint.createRecord( serviceName, serviceHost, servicePort, serviceRoot ) } }

Slide 82

Slide 82 text

#BSGTHEPLAN #BDXIO17 Raider(s) | s’enregistrer / metadata class Raider : AbstractVerticle() { override fun start() { // add metadata record?.metadata = json { obj( "kind" to "raider", "message" to " ready to fight", "basestar" to null, "coordinates" to obj( "x" to random(0.0, 400.0), "y" to random(0.0, 400.0) ), "app_id" to (System.getenv("APP_ID") ?: ""), "instance_id" to (System.getenv("INSTANCE_ID") ?: ""), "instance_type" to (System.getenv("INSTANCE_TYPE") ?: "production"), "instance_number" to (Integer.parseInt(System.getenv("INSTANCE_NUMBER") ?: "0")) ) } } }

Slide 83

Slide 83 text

#BSGTHEPLAN #BDXIO17 Raider(s) | s’enregistrer / démarrer class Raider : AbstractVerticle() { override fun start() { val httpPort = System.getenv("PORT")?.toInt() ?: 8080 vertx.createHttpServer(HttpServerOptions(port = httpPort)) .requestHandler { router.accept(it) } .listen { ar -> when { ar.failed() -> println(" Houston?") ar.succeeded() -> { println(" Raider started on $httpPort") /* === publish the microservice record to the discovery backend === */ discovery?.publish(record, { asyncRes -> when { asyncRes.failed() -> println(" ${asyncRes.cause().message}") asyncRes.succeeded() -> { println(" ${asyncRes.result().registration}") /* === search for a baseStar === */ searchAndSelectOneBaseStar() } } }) /* === end of publish === } } } } }

Slide 84

Slide 84 text

#BSGTHEPLAN #BDXIO17 Raider(s) | s’enregistrer / démarrer class Raider : AbstractVerticle() { override fun start() { val httpPort = System.getenv("PORT")?.toInt() ?: 8080 vertx.createHttpServer(HttpServerOptions(port = httpPort)) .requestHandler { router.accept(it) } .listen { ar -> when { ar.failed() -> println(" Houston?") ar.succeeded() -> { println(" Raider started on $httpPort") /* === publish the microservice record to the discovery backend === */ discovery?.publish(record, { asyncRes -> when { asyncRes.failed() -> println(" ${asyncRes.cause().message}") asyncRes.succeeded() -> { println(" ${asyncRes.result().registration}") /* === search for a baseStar === */ searchAndSelectOneBaseStar() } } }) /* === end of publish === } } } } }

Slide 85

Slide 85 text

#BSGTHEPLAN #BDXIO17 Raider Routes | Router

Slide 86

Slide 86 text

#BSGTHEPLAN #BDXIO17 Raider(s) // ⚠ call by a basestar router.post("/api/coordinates").handler { context -> // check data -> if null, don't move val computedX = context.bodyAsJson.getDouble("x") ?: x val computedY = context.bodyAsJson.getDouble("y") ?: y val computedXVelocity = context.bodyAsJson.getDouble("xVelocity") ?: xVelocity val computedYVelocity = context.bodyAsJson.getDouble("yVelocity") ?: yVelocity /* === updating record of the service === */ record?.metadata?.getJsonObject("coordinates") ?.put("x", computedX) ?.put("y",computedY) ?.put("xVelocity",computedXVelocity) ?.put("yVelocity",computedYVelocity) record?.metadata?.put("basestar", json {obj( "name:" to baseStar?.record?.name, "color" to baseStar?.record?.metadata?.get("color") )}) discovery?.update(record, {asyncUpdateResult -> }) context .response().putHeader("content-type", "application/json;charset=UTF-8") .end(json {obj( "message" to "", "x" to computedX, "y" to computedY )}.toString()) }

Slide 87

Slide 87 text

#BSGTHEPLAN #BDXIO17 Raider(s) // ⚠ call by a basestar router.post("/api/coordinates").handler { context -> // check data -> if null, don't move val computedX = context.bodyAsJson.getDouble("x") ?: x val computedY = context.bodyAsJson.getDouble("y") ?: y val computedXVelocity = context.bodyAsJson.getDouble("xVelocity") ?: xVelocity val computedYVelocity = context.bodyAsJson.getDouble("yVelocity") ?: yVelocity /* === updating record of the service === */ record?.metadata?.getJsonObject("coordinates") ?.put("x", computedX) ?.put("y",computedY) ?.put("xVelocity",computedXVelocity) ?.put("yVelocity",computedYVelocity) record?.metadata?.put("basestar", json {obj( "name:" to baseStar?.record?.name, "color" to baseStar?.record?.metadata?.get("color") )}) discovery?.update(record, {asyncUpdateResult -> }) context .response().putHeader("content-type", "application/json;charset=UTF-8") .end(json {obj( "message" to "", "x" to computedX, "y" to computedY )}.toString()) }

Slide 88

Slide 88 text

#BSGTHEPLAN #BDXIO17 Raider CircuitBreaker

Slide 89

Slide 89 text

#BSGTHEPLAN #BDXIO17 CircuitBreaker toc toc Penny ? toc toc Penny ? toc toc Penny ? ok j’arrête

Slide 90

Slide 90 text

#BSGTHEPLAN #BDXIO17 Raider(s) | circuitbreaker /* === Define a circuit breaker === */ breaker = CircuitBreaker.create("bsg-circuit-breaker", vertx, CircuitBreakerOptions( maxFailures = 5, timeout = 20000, fallbackOnFailure = true, resetTimeout = 100000))

Slide 91

Slide 91 text

#BSGTHEPLAN #BDXIO17 Raider /* === search for a baseStar === */ searchAndSelectOneBaseStar()

Slide 92

Slide 92 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun searchAndSelectOneBaseStar() { /* === search for a baseStar in the discovery backend === */ discovery?.getRecords( {r -> r.metadata.getString("kind") == "basestar" && r.status == io.vertx.servicediscovery.Status.UP }, { asyncResult -> when { asyncResult.failed() -> { } // asyncResult.succeeded() -> { // val baseStarsRecords = asyncResult.result() // === choose randomly a basestar === baseStarsRecords.size.let { when(it) { 0 -> { searchAndSelectOneBaseStar()/* oh oh no basestar online ?!!! */ } else -> { val selectedRecord = baseStarsRecords.get(Random().nextInt(it)) subscribeToBaseStar(selectedRecord) // } } } } } } ) // ⬅ end of the discovery }

Slide 93

Slide 93 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun searchAndSelectOneBaseStar() { /* === search for a baseStar in the discovery backend === */ discovery?.getRecords( {r -> r.metadata.getString("kind") == "basestar" && r.status == io.vertx.servicediscovery.Status.UP }, { asyncResult -> when { asyncResult.failed() -> { } // asyncResult.succeeded() -> { // val baseStarsRecords = asyncResult.result() // === choose randomly a basestar === baseStarsRecords.size.let { when(it) { 0 -> { searchAndSelectOneBaseStar() /* oh oh no basestar online ?!!! */ } else -> { val selectedRecord = baseStarsRecords.get(Random().nextInt(it)) subscribeToBaseStar(selectedRecord) // } } } } } } ) // ⬅ end of the discovery }

Slide 94

Slide 94 text

#BSGTHEPLAN #BDXIO17 Raider subscribeToBaseStar(selectedRecord) //

Slide 95

Slide 95 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun subscribeToBaseStar(selectedRecord: Record) { val serviceReference = discovery?.getReference(selectedRecord) val webClient = serviceReference?.getAs(WebClient::class.java) // === CIRCUIT BREAKER === try to register to the basestar breaker?.execute({ future -> webClient?.post("/api/raiders")?.sendJson(json { obj("registration" to record?.registration )}, { baseStarResponse -> when { baseStarResponse.failed() -> { this.baseStar = null // remove the basestar future.fail(" ouch something bad happened") } baseStarResponse.succeeded() -> { println(" you found a basestar") val selectedBaseStar = BaseStar(selectedRecord, webClient) this.baseStar = selectedBaseStar // time to check the health of my basestar watchingMyBaseStar(selectedBaseStar) future.complete(" yesss!") } } }) })?.setHandler({ breakerResult -> }) }

Slide 96

Slide 96 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun subscribeToBaseStar(selectedRecord: Record) { val serviceReference = discovery?.getReference(selectedRecord) val webClient = serviceReference?.getAs(WebClient::class.java) // === CIRCUIT BREAKER === try to register to the basestar breaker?.execute({ future -> webClient?.post("/api/raiders")?.sendJson(json { obj("registration" to record?.registration )}, { baseStarResponse -> when { baseStarResponse.failed() -> { this.baseStar = null // remove the basestar future.fail(" ouch something bad happened") } baseStarResponse.succeeded() -> { println(" you found a basestar") val selectedBaseStar = BaseStar(selectedRecord, webClient) this.baseStar = selectedBaseStar // time to check the health of my basestar watchingMyBaseStar(selectedBaseStar) future.complete(" yesss!") } } }) })?.setHandler({ breakerResult -> }) }

Slide 97

Slide 97 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun subscribeToBaseStar(selectedRecord: Record) { val serviceReference = discovery?.getReference(selectedRecord) val webClient = serviceReference?.getAs(WebClient::class.java) // === CIRCUIT BREAKER === try to register to the basestar breaker?.execute({ future -> webClient?.post("/api/raiders")?.sendJson(json { obj("registration" to record?.registration )}, { baseStarResponse -> when { baseStarResponse.failed() -> { this.baseStar = null // remove the basestar future.fail(" ouch something bad happened") } baseStarResponse.succeeded() -> { println(" you found a basestar") val selectedBaseStar = BaseStar(selectedRecord, webClient) this.baseStar = selectedBaseStar // time to check the health of my basestar watchingMyBaseStar(selectedBaseStar) future.complete(" yesss!") } } }) })?.setHandler({ breakerResult -> }) } ⚠⚠⚠

Slide 98

Slide 98 text

#BSGTHEPLAN #BDXIO17 Raider // time to check the health of my basestar watchingMyBaseStar(selectedBaseStar)

Slide 99

Slide 99 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun watchingMyBaseStar(baseStar: BaseStar) { // oh oh a B vertx.setPeriodic(1000, { timerId -> baseStar.client.get("/health").send { asyncGetRes -> when { asyncGetRes.failed() -> { record?.metadata?.getJsonObject("coordinates") ?.put("xVelocity",0) ?.put("yVelocity",0) // btw, you never stop in space discovery?.update(record, {asyncUpdateResult -> println("${record?.name} I'm alone ?") // time to search a new basestar searchAndSelectOneBaseStar() vertx.setTimer(3000, { id -> vertx.cancelTimer(timerId) }) }) } asyncGetRes.succeeded() -> { // === all is fine === } } } }) }

Slide 100

Slide 100 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun watchingMyBaseStar(baseStar: BaseStar) { // oh oh a B vertx.setPeriodic(1000, { timerId -> baseStar.client.get("/health").send { asyncGetRes -> when { asyncGetRes.failed() -> { record?.metadata?.getJsonObject("coordinates") ?.put("xVelocity",0) ?.put("yVelocity",0) // btw, you never stop in space discovery?.update(record, {asyncUpdateResult -> println("${record?.name} I'm alone ?") // time to search a new basestar searchAndSelectOneBaseStar() vertx.setTimer(3000, { id -> vertx.cancelTimer(timerId) }) }) } asyncGetRes.succeeded() -> { // === all is fine === } } } }) }

Slide 101

Slide 101 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun watchingMyBaseStar(baseStar: BaseStar) { // oh oh a B vertx.setPeriodic(1000, { timerId -> baseStar.client.get("/health").send { asyncGetRes -> when { asyncGetRes.failed() -> { record?.metadata?.getJsonObject("coordinates") ?.put("xVelocity",0) ?.put("yVelocity",0) // btw, you never stop in space discovery?.update(record, {asyncUpdateResult -> println("${record?.name} I'm alone ?") // time to search a new basestar searchAndSelectOneBaseStar() vertx.setTimer(3000, { id -> vertx.cancelTimer(timerId) }) }) } asyncGetRes.succeeded() -> { // === all is fine === } } } }) }

Slide 102

Slide 102 text

#BSGTHEPLAN #BDXIO17 Raider(s) fun watchingMyBaseStar(baseStar: BaseStar) { // oh oh a B vertx.setPeriodic(1000, { timerId -> baseStar.client.get("/health").send { asyncGetRes -> when { asyncGetRes.failed() -> { record?.metadata?.getJsonObject("coordinates") ?.put("xVelocity",0) ?.put("yVelocity",0) // btw, you never stop in space discovery?.update(record, {asyncUpdateResult -> println("${record?.name} I'm alone ?") // time to search a new basestar searchAndSelectOneBaseStar() vertx.setTimer(3000, { id -> vertx.cancelTimer(timerId) }) }) } asyncGetRes.succeeded() -> { // === all is fine === } } } }) }

Slide 103

Slide 103 text

#BSGTHEPLAN #BDXIO17 Récapitulatif BaseStar JAVA BaseStar JAVA BaseStar JAVA REDIS BaseStar JAVA GET http://localhost:808N/api/raiders POST http://localhost:808N/api/raiders GET http://localhost:808N/health BSG monitor SCALA GET http://localhost:8080/api/raiders BSG map JS http://localhost:7070 BaseStar JAVA Raider KOTLIN Raider KOTLIN Raider GROOVY Raider GROOVY POST http://localhost:909N/api/coordinates Raider GROOVY Raider KOTLIN Raider GROOVY GET http://localhost:909N/health POST http://localhost:808N/api/raiders POST http://localhost:909N/api/coordinates GET http://localhost:808N/health

Slide 104

Slide 104 text

#BSGTHEPLAN #BDXIO17 checklist ✅ Démarrer les BaseStars ✅ cf Base Redis - MEDIS ✅ Démarrer Redis ✅ Démarrer BSG Monitor ✅ Démarrer BSG Map ✅ Démarrer Raiders (kotlin) ✅ Tuer des BaseStars

Slide 105

Slide 105 text

#BSGTHEPLAN #BDXIO17 Faker Raider(s)

Slide 106

Slide 106 text

#BSGTHEPLAN #BDXIO17 ServiceDiscoveryRestEndpoint.java // use me with other microservices ServiceDiscoveryRestEndpoint.create(router, discovery); http://localhost:8081/discovery #BSGTHEPLAN #BDXIO17

Slide 107

Slide 107 text

#BSGTHEPLAN #BDXIO17 checklist ✅ Démarrer les BaseStars ✅ cf Base Redis - MEDIS ✅ Démarrer Redis ✅ Démarrer BSG Monitor ✅ Démarrer BSG Map ✅ Démarrer Raiders (kotlin) ✅ Tuer des BaseStars ✅ http://localhost:8080/discovery ✅ Démarrer Fake-Raider (Node) ✅ Démarrer Raiders (groovy) ✅ Ajouter des BaseStars

Slide 108

Slide 108 text

#BSGTHEPLAN #BDXIO17 Conclusion(s) - Remarques - Perspectives #BSGTHEPLAN #BDXIO17

Slide 109

Slide 109 text

#BSGTHEPLAN #BDXIO17 Perspectives • Déploiement sur le cloud, j’ai eu des surprises / API Management • Remettre à plat mon code | Refactoring • Ecrire un autre ServiceDiscoveryBackend (Redis PubSub, MQTT, …) • Utilisation d’un reverse proxy (peut-être) • Ajouter les 12 colonies dans la démo • Sécurité - Authentification https://github.com/botsgarden/vertx-service-discovery-backend-redisson

Slide 110

Slide 110 text

#BSGTHEPLAN #BDXIO17 Merci D • Vous • BDX.io • Clément Escoffier | Julien Viet | Julien Ponge

Slide 111

Slide 111 text

#BSGTHEPLAN #BDXIO17 Questions https://github.com/the-plan