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”
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
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")) ) } } }
{ 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()) }
{ 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()) }
discovery?.getReference(selectedRecord) val webClient = serviceReference?.getAs(WebClient::class.java) // === CIRCUIT BREAKER === try to register to the basestar breaker?.execute<String>({ 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 -> }) }
discovery?.getReference(selectedRecord) val webClient = serviceReference?.getAs(WebClient::class.java) // === CIRCUIT BREAKER === try to register to the basestar breaker?.execute<String>({ 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 -> }) }
discovery?.getReference(selectedRecord) val webClient = serviceReference?.getAs(WebClient::class.java) // === CIRCUIT BREAKER === try to register to the basestar breaker?.execute<String>({ 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 -> }) } ⚠⚠⚠
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 === } } } }) }
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 === } } } }) }
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 === } } } }) }
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 === } } } }) }
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
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