From 31b5fdc6ede4719a64779f20fdd7ddab63802c52 Mon Sep 17 00:00:00 2001 From: Ananto30 Date: Sat, 23 Jan 2021 18:01:06 +0600 Subject: [PATCH] Fix dockerfile and main --- Dockerfile | 9 ++- README.md | 31 ++++++++-- java_run.sh | 5 ++ make_two_docker_instances.sh | 12 ++++ pom.xml | 32 +++++++++- .../java/com/ananto/asyncgateway/DevApp.java | 59 +++++++++++++++++++ .../com/ananto/asyncgateway/MainVerticle.java | 56 +++--------------- src/main/resources/logback.xml | 16 +++++ 8 files changed, 164 insertions(+), 56 deletions(-) create mode 100644 java_run.sh create mode 100644 make_two_docker_instances.sh create mode 100644 src/main/java/com/ananto/asyncgateway/DevApp.java create mode 100644 src/main/resources/logback.xml diff --git a/Dockerfile b/Dockerfile index 08ba4e1..77830c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,8 @@ FROM openjdk:11-jre-slim -# copy application WAR (with libraries inside) + COPY target/starter-1.0.0-SNAPSHOT-fat.jar /app.jar -# specify default command -CMD ["java", "-jar", "/app.jar", "-cluster"] + +ENV CLUSTER_PUBLIC_PORT 17001 +ENV CLUSTER_PUBLIC_HOST 192.168.0.100 + +CMD java -jar /app.jar -cluster -cluster-public-port $CLUSTER_PUBLIC_PORT -cluster-public-host $CLUSTER_PUBLIC_HOST -instance 4 diff --git a/README.md b/README.md index 1dfa675..fa11824 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,33 @@ Example of converting (legacy) async service to sync. -## IMPORTANT! +## Run for dev +Directly run the DevApp. All the tweaks can be done with the code. -Change the `EVENT_BUS_CLUSTER_PUBLIC_HOST` with your machine IP. (for dev) +## Run for production/testing +Can be run using the fat jar. +Create jar: +``` +./mvnw clean package +``` +Or skip tests: +``` +./mvnw clean package -Dmaven.test.skip=true +``` +____________________ +Run with java: +``` +java -jar target/starter-1.0.0-SNAPSHOT-fat.jar -cluster -cluster-public-port 17001 -cluster-public-host -instance 4 +``` +**Important notes:** +The `-cluster` ensures verticles are running in cluster mode, so the event bus can communicate with all the verticles even if they are running in different machines. + +`-cluster-public-port` is the public exposing port where the other clusters can connect to. + +`-cluster-public-host` is **really important**. You should expose the IP of your machines so that other clusters can connect to it. + +`-instance` is how many instances you want to run. Can be your core numbers, but better play with it. Especially each instance has a single eventloop. ## Test with Docker Create jar: @@ -24,8 +47,8 @@ docker build -t vertx-async-gateway . Docker run two instances exposed with different ports: ``` -docker run -p 8888:8888 -d vertx-async-gateway -docker run -p 8889:8888 -d vertx-async-gateway +docker run -p 8888:8888 -e cluster-public-host= -d vertx-async-gateway +docker run -p 8889:8888 -e cluster-public-host= -d vertx-async-gateway ``` **To test properly use something like nginx to load balance among 8888 and 8889** diff --git a/java_run.sh b/java_run.sh new file mode 100644 index 0000000..cff8842 --- /dev/null +++ b/java_run.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env sh + +./mvnw clean package -Dmaven.test.skip=true + +java -jar target/starter-1.0.0-SNAPSHOT-fat.jar -cluster -cluster-host 192.168.0.100 -instance 4 diff --git a/make_two_docker_instances.sh b/make_two_docker_instances.sh new file mode 100644 index 0000000..811b702 --- /dev/null +++ b/make_two_docker_instances.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +docker rm -f vertx-async-gateway-1 +docker rm -f vertx-async-gateway-2 + +./mvnw clean package -Dmaven.test.skip=true + +docker build -t ananto30/vertx-example:vertx-async-gateway . +docker push ananto30/vertx-example:vertx-async-gateway + +docker run --name vertx-async-gateway-1 -p 8888:8888 -e CLUSTER_PUBLIC_HOST=192.168.0.119 -d ananto30/vertx-example:vertx-async-gateway +docker run --name vertx-async-gateway-2 -p 8889:8888 -e CLUSTER_PUBLIC_HOST=192.168.0.100 -d vertx-async-gateway diff --git a/pom.xml b/pom.xml index c81299a..5b0db86 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.example @@ -49,6 +49,34 @@ vertx-hazelcast + + + + + + + + + + + + + + + + + + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + io.vertx vertx-junit5 diff --git a/src/main/java/com/ananto/asyncgateway/DevApp.java b/src/main/java/com/ananto/asyncgateway/DevApp.java new file mode 100644 index 0000000..67a9484 --- /dev/null +++ b/src/main/java/com/ananto/asyncgateway/DevApp.java @@ -0,0 +1,59 @@ +package com.ananto.asyncgateway; + +import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; +import io.vertx.core.eventbus.EventBus; +import io.vertx.core.eventbus.EventBusOptions; +import io.vertx.spi.cluster.hazelcast.HazelcastClusterManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Azizul Haque Ananto + * @since 22/1/21 + */ +public class DevApp { + + private static final String EVENT_BUS_CLUSTER_PUBLIC_HOST = "192.168.0.100"; // IMPORTANT! for dev, IP of your machine + private static final int EVENT_BUS_CLUSTER_PUBLIC_PORT = 17001; + + private static final Logger logger = LoggerFactory.getLogger(DevApp.class); + + public static void main(String[] args) { + /* + IMPORTANT!!! + The main method is only used in development mode, when run from intellij or calling the main method directly + */ + System.setProperty("vertx.logger-delegate-factory-class-name", "io.vertx.core.logging.SLF4JLogDelegateFactory"); + VertxOptions options = new VertxOptions() + .setClusterManager(new HazelcastClusterManager()) // hazlecast is distributed in-memory data grid that can track the distributed clusters + // for kubernetes - https://vertx.io/docs/vertx-hazelcast/java/#_configuring_for_kubernetes + + // this is where all the magic happens :D + // the cluster implementation of the event bus allows different instances to talk with each other through tcp network + // basically it's a distributed event bus now + .setEventBusOptions(new EventBusOptions() + // the most important part! public host can be different for each instance + // for kubernetes we can use the service host most probably + .setClusterPublicHost(EVENT_BUS_CLUSTER_PUBLIC_HOST) + .setClusterPublicPort(EVENT_BUS_CLUSTER_PUBLIC_PORT) + + ); + Vertx.clusteredVertx(options, res -> { + if (res.succeeded()) { + Vertx vertx = res.result(); + + // we can deploy multiple verticles using same vertx manager to utilize cores + vertx.deployVerticle(new MainVerticle()); + vertx.deployVerticle(new MainVerticle()); + vertx.deployVerticle(new MainVerticle()); + vertx.deployVerticle(new MainVerticle()); + + EventBus eventBus = vertx.eventBus(); + logger.info("We now have a clustered event bus: " + eventBus); + } else { + logger.error("Failed: {}", res.cause(), res.cause()); + } + }); + } +} diff --git a/src/main/java/com/ananto/asyncgateway/MainVerticle.java b/src/main/java/com/ananto/asyncgateway/MainVerticle.java index b8dbaee..c698587 100644 --- a/src/main/java/com/ananto/asyncgateway/MainVerticle.java +++ b/src/main/java/com/ananto/asyncgateway/MainVerticle.java @@ -2,10 +2,6 @@ import io.vertx.core.AbstractVerticle; import io.vertx.core.Promise; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import io.vertx.core.eventbus.EventBus; -import io.vertx.core.eventbus.EventBusOptions; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerResponse; import io.vertx.core.json.JsonObject; @@ -13,9 +9,9 @@ import io.vertx.ext.web.handler.BodyHandler; import io.vertx.ext.web.handler.LoggerHandler; import io.vertx.ext.web.handler.TimeoutHandler; -import io.vertx.spi.cluster.hazelcast.HazelcastClusterManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; public class MainVerticle extends AbstractVerticle { @@ -23,8 +19,8 @@ public class MainVerticle extends AbstractVerticle { private static final int PORT = 8888; private static final String ASYNC_RESULT_EVENT = "async.result"; private static final long DEFAULT_REQUEST_TIMEOUT = 10000L; - private static final String EVENT_BUS_CLUSTER_PUBLIC_HOST = "192.168.0.100"; // IMPORTANT! for dev, IP of your machine - private static final int EVENT_BUS_CLUSTER_PUBLIC_PORT = 17001; + + private static final Logger logger = LoggerFactory.getLogger(MainVerticle.class); @Override @@ -40,8 +36,7 @@ public void start(Promise startPromise) throws Exception { router.route().handler(BodyHandler.create()); router.route().handler(TimeoutHandler.create(DEFAULT_REQUEST_TIMEOUT)); // change default timeout to 10sec router.route().failureHandler(ctx -> { - System.out.println(ctx.failure().getMessage()); - System.out.println(Arrays.toString(ctx.failure().getStackTrace())); + logger.error(ctx.failure().getMessage(), ctx.failure()); ctx.next(); }); @@ -56,7 +51,7 @@ public void start(Promise startPromise) throws Exception { server.requestHandler(router).listen(PORT, http -> { if (http.succeeded()) { startPromise.complete(); - System.out.println("HTTP server started on port " + PORT); + logger.info("HTTP server started on port " + PORT); requestProcessor(requests); } else { startPromise.fail(http.cause()); @@ -68,11 +63,11 @@ private void requestProcessor(ConcurrentHashMap requ vertx.eventBus().consumer(ASYNC_RESULT_EVENT).handler(data -> { var body = (JsonObject) data.body(); var id = body.getString("id"); - System.out.printf("Event received | %s : %s%n", id, body); + logger.info(String.format("Event received | %s : %s%n", id, body)); var entry = requests.get(id); if (entry != null) { - entry.end(body.toString()); - requests.remove(id); + if (entry.ended()) requests.remove(id);// timout request + else entry.end(body.toString()); } }); } @@ -92,38 +87,5 @@ private void asyncHandler(io.vertx.ext.web.RoutingContext ctx, ConcurrentHashMap requests.put(id, response); } - - public static void main(String[] args) { - VertxOptions options = new VertxOptions() - .setClusterManager(new HazelcastClusterManager()) // hazlecast is distributed in-memory data grid that can track the distributed clusters - // for kubernetes - https://vertx.io/docs/vertx-hazelcast/java/#_configuring_for_kubernetes - - // this is where all the magic happens :D - // the cluster implementation of the event bus allows different instances to talk with each other through tcp network - // basically it's a distributed event bus now - .setEventBusOptions(new EventBusOptions() - // the most important part! public host can be different for each instance - // for kubernetes we can use the service host most probably - .setClusterPublicHost(EVENT_BUS_CLUSTER_PUBLIC_HOST) - .setClusterPublicPort(EVENT_BUS_CLUSTER_PUBLIC_PORT) - - ); - Vertx.clusteredVertx(options, res -> { - if (res.succeeded()) { - Vertx vertx = res.result(); - - // we can deploy multiple verticles using same vertx manager to utilize cores - vertx.deployVerticle(new MainVerticle()); - vertx.deployVerticle(new MainVerticle()); - vertx.deployVerticle(new MainVerticle()); - vertx.deployVerticle(new MainVerticle()); - - EventBus eventBus = vertx.eventBus(); - System.out.println("We now have a clustered event bus: " + eventBus); - } else { - System.out.println("Failed: " + res.cause()); - } - }); - } } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..0d8a143 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + %d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %5p | %-25.25logger{25} | %12(ID: %8mdc{id}) | %m%n + + + + + + + + + +