├── .gitignore ├── README.md ├── README_KOR.md ├── aggregation-http ├── A │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── config │ │ │ └── config.json │ │ ├── java │ │ │ └── io │ │ │ │ └── vertx │ │ │ │ └── microservices │ │ │ │ ├── A.java │ │ │ │ ├── MainVerticle.java │ │ │ │ └── OpenshiftVerticle.java │ │ └── resources │ │ │ └── assets │ │ │ ├── circuits.html │ │ │ ├── discovery.html │ │ │ ├── index.html │ │ │ └── libs │ │ │ └── vertx-eventbus.js │ │ └── openshift │ │ └── config.json ├── B │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── config │ │ │ └── config.json │ │ └── java │ │ │ └── io │ │ │ └── vertx │ │ │ └── microservices │ │ │ ├── B.java │ │ │ └── MainVerticle.java │ │ └── openshift │ │ └── config.json ├── C │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── config │ │ │ └── config.json │ │ └── java │ │ │ └── io │ │ │ └── vertx │ │ │ └── microservices │ │ │ ├── C.java │ │ │ └── MainVerticle.java │ │ └── openshift │ │ └── config.json ├── D │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── config │ │ │ └── config.json │ │ └── java │ │ │ └── io │ │ │ └── vertx │ │ │ └── microservices │ │ │ ├── D.java │ │ │ └── MainVerticle.java │ │ └── openshift │ │ └── config.json ├── etc │ ├── cluster.xml │ └── vertx-eventbus-service.json └── pom.xml ├── img ├── aggregation-page.png ├── get-service-ip.png ├── openshift-login.png ├── openshift-pods.png ├── openshift-scaling-down.png └── pipeline-page.png ├── pipeline-http ├── A │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── config │ │ │ └── config.json │ │ ├── java │ │ │ └── io │ │ │ │ └── vertx │ │ │ │ └── microservices │ │ │ │ ├── A.java │ │ │ │ ├── MainVerticle.java │ │ │ │ └── OpenshiftVerticle.java │ │ └── resources │ │ │ └── assets │ │ │ └── index.html │ │ └── openshift │ │ └── config.json ├── B │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── config │ │ │ └── config.json │ │ └── java │ │ │ └── io │ │ │ └── vertx │ │ │ └── microservices │ │ │ ├── B.java │ │ │ ├── MainVerticle.java │ │ │ └── OpenshiftVerticle.java │ │ └── openshift │ │ └── config.json ├── C │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── config │ │ │ └── config.json │ │ └── java │ │ │ └── io │ │ │ └── vertx │ │ │ └── microservices │ │ │ ├── C.java │ │ │ ├── MainVerticle.java │ │ │ └── OpenshiftVerticle.java │ │ └── openshift │ │ └── config.json ├── D │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── config │ │ │ └── config.json │ │ └── java │ │ │ └── io │ │ │ └── vertx │ │ │ └── microservices │ │ │ ├── D.java │ │ │ ├── MainVerticle.java │ │ │ └── OpenshiftVerticle.java │ │ └── openshift │ │ └── config.json ├── README.md ├── README_KOR.MD ├── etc │ ├── cluster.xml │ └── vertx-eventbus-service.json └── pom.xml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | ### Maven template 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | pom.xml.next 7 | release.properties 8 | dependency-reduced-pom.xml 9 | buildNumber.properties 10 | .mvn/timing.properties 11 | ### Java template 12 | *.class 13 | 14 | # Mobile Tools for Java (J2ME) 15 | .mtj.tmp/ 16 | 17 | # Package Files # 18 | *.jar 19 | *.war 20 | *.ear 21 | 22 | .vertx 23 | 24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 25 | hs_err_pid* 26 | .settings 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vert.x Microservices examples 2 | 3 | This repository demonstrates how to build two common microservice patterns with vert.x: 4 | 5 | 1. aggregation 6 | 2. pipeline 7 | 8 | It uses vert.x discovery, circuit breaker and if you run them on Openshift Origin, Kubernetes discovery. 9 | 10 | In an aggregation, a microservice aggregates the results from other microservices. In this example, A calls B, C 11 | and D and returns the aggregated answer to the client. 12 | 13 | In a pipeline, a microservice is calling another one, calling another one... In this example, A calls B, B calls C 14 | and C calls D. The client get the whole result. 15 | 16 | In these examples, microservice communicates using HTTP. However this is not requires and you can use asynchronous 17 | service proxies, events, SOAP or whatever protocol you like. 18 | 19 | ## Run the demos locally 20 | 21 | First, you need to build the projects, with: 22 | 23 | ``` 24 | mvn clean install 25 | ``` 26 | 27 | Be aware that the microservices are going to open the port: 8080 (A), 8081 (B), 8082 (C), and 8083 (D). This is 28 | configurable in the configuration files. 29 | 30 | ### Aggregation example 31 | 32 | First go in the `aggregation-http` directory, and open 4 terminals (one for each microservice) 33 | 34 | ``` 35 | cd aggregation-http 36 | ``` 37 | 38 | Then, launch the microservices: 39 | 40 | ``` 41 | cd A 42 | java -Djava.net.preferIPv4Stack=true -jar target/aggregation-http-A-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 43 | ``` 44 | 45 | ``` 46 | cd B 47 | java -Djava.net.preferIPv4Stack=true -jar target/aggregation-http-B-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 48 | ``` 49 | 50 | ``` 51 | cd C 52 | java -Djava.net.preferIPv4Stack=true -jar target/aggregation-http-C-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 53 | ``` 54 | 55 | ``` 56 | cd D 57 | java -Djava.net.preferIPv4Stack=true -jar target/aggregation-http-D-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 58 | ``` 59 | 60 | Let's analyses these command lines: 61 | 62 | * it uses IPv4 just to avoid some networking issues 63 | * it launches the microservice (vert.x application) using the _fat jar_ build during the Maven build 64 | * the vert.x application is started in cluster mode and get some configuration data 65 | 66 | The cluster is using Hazelcast and is configured in the `../etc/cluster.xml` file. By default it uses `127.0.0.1`. 67 | 68 | Once launch, open a browser to `http://localhost:8080/assets/index.html`. You should get a web page inviting you to 69 | submit a form that will execute the application: 70 | 71 | ![the aggregation application page](img/aggregation-page.png "The aggregation application page") 72 | 73 | If everything is launched, you should get: `{"A":"Hello vert.x","B":"Hola vert.x","C":"No service available (no 74 | record)","D":"Aloha vert.x"}`. 75 | 76 | Now shutdown one of the application (B, C or D), by hitting `CTRL+C` in the right terminal. Re-submit the form. You 77 | should get: `{"A":"Hello vert.x","B":"Hola vert.x","C":"No service available (no record)","D":"Aloha vert.x"}` or 78 | something similar. 79 | 80 | When shutting down a microservice, it does not reply to the request anymore. The circuit breaker intercepts the error 81 | and execute a fallback. If you restarts it, the output should be back to _normal_. This is because the circuit 82 | breaker tries periodically to reset its state and check whether or not things are back to _normal_. 83 | 84 | 85 | ### Pipeline example 86 | 87 | First go in the `pipeline-http` directory, and open 4 terminals (one for each microservice) 88 | 89 | ``` 90 | cd pipeline-http 91 | ``` 92 | 93 | Then, launch the microservices: 94 | 95 | ``` 96 | cd A 97 | java -Djava.net.preferIPv4Stack=true -jar target/pipeline-http-A-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 98 | ``` 99 | 100 | ``` 101 | cd B 102 | java -Djava.net.preferIPv4Stack=true -jar target/pipeline-http-B-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 103 | ``` 104 | 105 | ``` 106 | cd C 107 | java -Djava.net.preferIPv4Stack=true -jar target/pipeline-http-C-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 108 | ``` 109 | 110 | ``` 111 | cd D 112 | java -Djava.net.preferIPv4Stack=true -jar target/pipeline-http-D-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 113 | ``` 114 | 115 | Let's analyses these command lines: 116 | 117 | * it uses IPv4 just to avoid some networking issues 118 | * it launches the microservice (vert.x application) using the _fat jar_ build during the Maven build 119 | * the vert.x application is started in cluster mode and get some configuration data 120 | 121 | The cluster is using Hazelcast and is configured in the `../etc/cluster.xml` file. By default it uses `127.0.0.1`. 122 | 123 | Once launch, open a browser to `http://localhost:8080/assets/index.html`. You should get a web page inviting you to 124 | submit a form that will execute the application: 125 | 126 | ![the pipeline application page](img/pipeline-page.png "The pipeline application page") 127 | 128 | 129 | If everything is launched, you should get: `{"D":"Aloha vert.x","C":"Olá vert.x","B":"Hola vert.x","A":"Hello vert.x"}`. 130 | 131 | Now shutdown one of the application (B, C or D), by hitting `CTRL+C` in the right terminal. Re-submit the form. You 132 | should get: `{"C":"No service available (fallback)","B":"Hola vert.x","A":"Hello vert.x"}` or 133 | something similar. 134 | 135 | When shutting down a microservice, it does not reply to the request anymore. The circuit breaker intercepts the error 136 | and execute a fallback. If you restarts it, the output should be back to _normal_. This is because the circuit 137 | breaker tries periodically to reset its state and check whether or not things are back to _normal_. 138 | 139 | ## Run the demos in Openshift Origin (v3) 140 | 141 | These demos can also be executed in Openshift. 142 | 143 | ### Prerequisites 144 | 145 | You will need to have Openshift on your machine to run them demo. 146 | 147 | Here is how to start Openshift using Docker on Linux: 148 | 149 | ``` 150 | docker rm origin 151 | sudo docker run -d --name "origin" \ 152 | --privileged --pid=host --net=host \ 153 | -v /:/rootfs:ro -v /var/run:/var/run:rw -v /sys:/sys -v /var/lib/docker:/var/lib/docker:rw \ 154 | -v /var/lib/origin/openshift.local.volumes:/var/lib/origin/openshift.local.volumes \ 155 | openshift/origin start 156 | docker logs -f origin 157 | ``` 158 | 159 | You would need the `oc` command line tool too. Download it form the Openshift web site. 160 | 161 | ### Login to openshift 162 | 163 | Once launched, execute: 164 | 165 | ``` 166 | oc login 167 | # credentials are admin / admin 168 | ``` 169 | 170 | Also connect with your browser on https://0.0.0.0:8443. The certificates are not valid, just force the access. You 171 | should arrive on a page similar to that one: 172 | 173 | ![Openshift login](img/openshift-login.png "The Openshift login page") 174 | 175 | ### Aggregation example 176 | 177 | 178 | **Step 1: Project creation** 179 | 180 | You first need to create the Openshift project, and give some permissions: 181 | 182 | ``` 183 | oc new-project vertx-microservice-example-aggregation-http 184 | oc policy add-role-to-user admin admin -n vertx-microservice-example-aggregation-http 185 | oc policy add-role-to-group view system:serviceaccounts -n vertx-microservice-example-aggregation-http 186 | ``` 187 | 188 | Do **not** change the project name, the configuration of the application is made for this name. See details below. 189 | 190 | **Runs the microservice** 191 | 192 | First go in the `aggregation-http` directory. Then for each project (A, B, C and D) runs: 193 | 194 | ``` 195 | mvn clean package docker:build fabric8:json fabric8:apply -Popenshift 196 | ``` 197 | 198 | It uses the Docker Maven plugin and the Fabric8 Maven plugin to build a docker image containing the microservice. It 199 | pushes it to the docker registry and creates the application in Openshift (using Kubernetes). 200 | 201 | When you have deployed all components, you should have 4 pods in openshift, one for each service: 202 | 203 | ![the Openshift pod and service list](img/openshift-pods.png "The Openshift pod and service list") 204 | 205 | To access the application page, you need to get the IP of the service `A`. To get this IP, click on the service `A` 206 | and get the IP in the right side panel: 207 | 208 | ![the Openshift pod and service list](img/openshift-pods.png "The Openshift pod and service list") 209 | 210 | Once you have the IP, open the page: http://$ip/assets/index.html 211 | 212 | You can use the application as the _local_ version. Then, go back to the Openshift overview page and scale down one 213 | of the service pod (B, C or D): 214 | 215 | ![scaling down a pod](img/openshift-scaling-down.png "Scaling down a pod") 216 | 217 | Try to reuse the application, the circuit breaker should detect the failure and use a fallback. If you restore the 218 | destroyed pod, the application should act _normally_ again. 219 | 220 | **Kubernetes and service discovery** 221 | 222 | When running in Openshift, the Kubernetes services are imported in the vert.x discovery service, so they are 223 | retrieved as _regular_ services by the application. 224 | 225 | ### Pipeline example 226 | 227 | **Step 1: Project creation** 228 | 229 | You first need to create the Openshift project, and give some permissions: 230 | 231 | ``` 232 | oc new-project vertx-microservice-example-pipeline-http 233 | oc policy add-role-to-user admin admin -n vertx-microservice-example-pipeline-http 234 | oc policy add-role-to-group view system:serviceaccounts -n vertx-microservice-example-pipeline-http 235 | ``` 236 | 237 | Do **not** change the project name, the configuration of the application is made for this name. See details below. 238 | 239 | **Runs the microservice** 240 | 241 | First go in the `pipeline-http` directory. Then for each project (A, B, C and D) runs: 242 | 243 | ``` 244 | mvn clean package docker:build fabric8:json fabric8:apply -Popenshift 245 | ``` 246 | 247 | It uses the Docker Maven plugin and the Fabric8 Maven plugin to build a docker image containing the microservice. It 248 | pushes it to the docker registry and creates the application in Openshift (using Kubernetes). 249 | 250 | When you have deployed all components, you should have 4 pods in openshift, one for each service: 251 | 252 | ![the Openshift pod and service list](img/openshift-pods.png "The Openshift pod and service list") 253 | 254 | To access the application page, you need to get the IP of the service `A`. To get this IP, click on the service `A` 255 | and get the IP in the right side panel: 256 | 257 | ![the Openshift pod and service list](img/openshift-pods.png "The Openshift pod and service list") 258 | 259 | Once you have the IP, open the page: http://$ip/assets/index.html 260 | 261 | You can use the application as the _local_ version. Then, go back to the Openshift overview page and scale down one 262 | of the service pod (B, C or D): 263 | 264 | ![scaling down a pod](img/openshift-scaling-down.png "Scaling down a pod") 265 | 266 | Try to reuse the application, the circuit breaker should detect the failure and use a fallback. If you restore the 267 | destroyed pod, the application should act _normally_ again. 268 | 269 | 270 | ### Trick to shutdown everything 271 | 272 | To shutdown openshift and the deployed pods use: 273 | 274 | ``` 275 | # On bash 276 | docker stop `docker ps -qa` 277 | docker rm -f `docker ps -qa` 278 | # Fish 279 | docker stop (docker ps -qa) 280 | docker rm -f (docker ps -qa) 281 | ``` 282 | -------------------------------------------------------------------------------- /README_KOR.md: -------------------------------------------------------------------------------- 1 | # Vert.x 마이크로서비스 예제 2 | 3 | 이번 예제에서는 vert.x로 자주 쓰이는 2개의 마이크로서비스 패턴을 구현해 볼 것 입니다. 4 | 5 | 1. aggregation 6 | 2. 파이프라인 7 | 8 | 이 예제는 vert.x discovery와 circuit breaker를 사용합니다. 9 | 그리고 만약 Openshift Origin 위에서 구동한다면 Kubernetes discovery를 사용합니다. 10 | 11 | 12 | aggreagation 패턴에서 마이크로서비스는 다른 마이크로서비스로부터 온 결과들을 모읍니다. 예를 들어 A는 B, C, D를 호출하고 클라이언트에게 합쳐진 결과를 보냅니다. 13 | 14 | 파이프라인 패턴에서는 마이크로서비스가 다른 서비스를 호출하고, 그 서비스가 또 다른 서비스를 호출합니다. 예를 들어 A가 B를 호출하고, B가 C를 호출하고, 15 | C가 D를 호출하고 나면, 클라이언트는 그 결과를 전부 얻습니다. 16 | 17 | 이번 예제에서는 마이크로서비스가 HTTP 프로토콜을 이용해 서로 통신을 합니다. 그러나 HTTP뿐만 아니라, 비동기 서비스 프록시, 이벤트 , SOAP와 같은 18 | 다른 어떠한 프로토콜을 사용해도 상관이 없습니다. 19 | 20 | ## 로컬에서 데모를 실행해봅시다. 21 | 22 | 우선, 다음과 같은 명령어로 프로젝트를 빌드해야 합니다.: 23 | 24 | ``` 25 | mvn clean install 26 | ``` 27 | 28 | 마이크로서비스는 8080 (A), 8081(B), 8082(C), 8083(D)의 각각 포트가 열려있어야만 한다는 점을 주의하세요! 이것은 설정파일에서 설정이 가능합니다. 29 | 30 | ### Aggregation 예제 31 | 32 | 우선 `aggregation-http` 디렉토리로 이동하세요, 그리고 4개의 터미널을 여세요.(각각의 터미널은 한개의 마이크로 서비스에 해당합니다.) 33 | 34 | ``` 35 | cd aggregation-http 36 | ``` 37 | 38 | 그리고나서, 마이크로서비스를 실행시키세요: 39 | 40 | ``` 41 | cd A 42 | java -Djava.net.preferIPv4Stack=true -jar target/aggregation-http-A-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 43 | ``` 44 | 45 | ``` 46 | cd B 47 | java -Djava.net.preferIPv4Stack=true -jar target/aggregation-http-B-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 48 | ``` 49 | 50 | ``` 51 | cd C 52 | java -Djava.net.preferIPv4Stack=true -jar target/aggregation-http-C-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 53 | ``` 54 | 55 | ``` 56 | cd D 57 | java -Djava.net.preferIPv4Stack=true -jar target/aggregation-http-D-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 58 | ``` 59 | 60 | 위의 명령어들을 분석해봅시다: 61 | 62 | * 각 명령어의 첫번째 부분은 몇가지 네트워크 이슈를 피하기 위해 IPv4 주소를 사용하는 것을 의미합니다. 63 | * 각 명령어의 두번째 부분은 메이븐을 통해 만들어진 _fat jar_ 을 이용해서 마이크로서비스(vert.x로 구현된 서비스)를 실행시키는 것 입니다. 64 | * 각 명령어의 세번째 부분은 vert.x 어플리케이션을 클러스터 모드로 실행시키고, 약간의 설정 정보를 가져옵니다. 65 | 66 | 클러스터는 Hazelcast를 사용하고 `../etc/cluster.xml` 파일에 설정정보가 있습니다. 그리고 기본적으로 `127.0.0.1` 주소를 사용합니다. 67 | 68 | 일단 실행되고 나면 브라우저를 열어서 `http://localhost:8080/assets/index.html` 로 접속하세요. 당신은 아마 폼을 제출하는 웹페이지를 보게 될 것입니다. 69 | 그리고 이 폼은 우리의 어플리케이션을 실행시킬 것 입니다. 70 | 71 | ![the aggregation application page](img/aggregation-page.png "The aggregation application page") 72 | 73 | 모든 것이 제대로 실행되면 당신은 다음과 같은 데이터를 얻게 됩니다: `{"A":"Hello vert.x","B":"Hola vert.x","C":"No service available (no 74 | record)","D":"Aloha vert.x"}`. 75 | 76 | 터미널에서 `CTRL+C`를 입력하여 B,C,D 중 하나의 서비스를 셧다운 시켜봅시다. 그리고 폼을 다시 제출해보세요. 77 | 당신은 아마 다음과 같은 데이터를 얻게 될 것입니다. `{"A":"Hello vert.x","B":"Hola vert.x","C":"No service available (no record)","D":"Aloha vert.x"}` 이 결과는 어떤 서비스를 종료시켰는지에 따라 조금 달라질 수 있습니다. 78 | 79 | 마이크로서비스를 종료시키고 나면, 더 이상 요청에 응답하지 않습니다. circuit breaker가 에러를 가로챌 것이고, fallback 함수를 실행시킬 것입니다.(역주: fallback은 어떤 것이 고장이나 작동불능일 때 대체하는 것을 말합니다.) 만약 서비스를 재실행하면, 출력은 아마 _정상_ 으로 돌아갈 것 입니다. 이것은 circuit breaker가 주기적으로 상태를 초기하고 _정상_ 으로 돌아갔는지 확인하기 때문입니다. 80 | 81 | 82 | ### 파이프라인 예제 83 | 84 | 우선, `pipeline-http` 디렉토리로 이동하고, 4개의 터미널을 실행시키세요. (각각의 터미널은 각각의 마이크로서비스를 의미합니다.) 85 | 86 | ``` 87 | cd pipeline-http 88 | ``` 89 | 90 | 그리고 마이크로서비스를 실행시키세요: 91 | 92 | ``` 93 | cd A 94 | java -Djava.net.preferIPv4Stack=true -jar target/pipeline-http-A-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 95 | ``` 96 | 97 | ``` 98 | cd B 99 | java -Djava.net.preferIPv4Stack=true -jar target/pipeline-http-B-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 100 | ``` 101 | 102 | ``` 103 | cd C 104 | java -Djava.net.preferIPv4Stack=true -jar target/pipeline-http-C-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 105 | ``` 106 | 107 | ``` 108 | cd D 109 | java -Djava.net.preferIPv4Stack=true -jar target/pipeline-http-D-1.0-SNAPSHOT-fat.jar -cluster -cp ../etc -conf src/main/config/config.json 110 | ``` 111 | 112 | 위의 명령어를 분석해봅시다: 113 | 114 | * 각 명령어의 첫번째 부분은 몇가지 네트워크 이슈를 피하기 위해 IPv4 주소를 사용하는 것을 의미합니다. 115 | * 각 명령어의 두번째 부분은 메이븐을 통해 만들어진 _fat jar_ 을 이용해서 마이크로서비스(vert.x로 구현된 서비스)를 실행시키는 것 입니다. 116 | * 각 명령어의 세번째 부분은 vert.x 어플리케이션을 클러스터 모드로 실행시키고, 약간의 설정 정보를 가져옵니다. 117 | 118 | 클러스터는 Hazelcast를 사용하고 `../etc/cluster.xml` 파일에 설정정보가 있습니다. 기본적으로 `127.0.0.1` 주소를 사용합니다. 119 | 120 | 일단 실행되고 나면 브라우저를 열어서 `http://localhost:8080/assets/index.html` 접속하세요. 당신은 아마 폼을 제출하는 웹페이지를 보게 될 것입니다. 121 | 그리고 이 폼이 우리의 어플리케이션을 실행시킬 것 입니다. 122 | 123 | ![the pipeline application page](img/pipeline-page.png "The pipeline application page") 124 | 125 | 126 | 모든 것이 제대로 실행되면 다음과 같은 데이터를 얻게 됩니다.: `{"D":"Aloha vert.x","C":"Olá vert.x","B":"Hola vert.x","A":"Hello vert.x"}`. 127 | 128 | B,C,D 중 아무 서비스나 터미널에서 `CTRL+C`를 입력해서 종료시켜봅시다. 다시 폼을 제출하면 다음과 같은 데이터를 얻게 됩니다: `{"C":"No service available (fallback)","B":"Hola vert.x","A":"Hello vert.x"}` 이 결과는 어떤 서비스를 종료시켰는지에 따라 조금 달라질 수 있습니다. 129 | 130 | 마이크로서비스를 종료시키고 나면, 더 이상 요청에 응답하지 않습니다. circuit breaker가 에러를 가로챌 것이고, fallback 함수를 실행시킬 것입니다.(역주: fallback은 어떤 것이 고장이나 작동불능일 때 대체하는 것을 말합니다.) 만약 당신이 서비스를 재실행하면, 출력은 아마 _정상_ 으로 돌아갈 것 입니다. 이것은 circuit breaker가 주기적으로 상태를 초기하고 _정상_ 으로 돌아갔는지 확인하기 때문입니다. 131 | 132 | ## Openshift Origin (v3)에서 데모 구동하기 133 | 134 | 이 데모는 Openshift에서 구동할 수 있습니다.. 135 | 136 | ### 요구사항 137 | 138 | 데모를 구동하기 위해서는 당신의 컴퓨터에 openshift가 설치되어 있어야 합니다. 139 | 140 | 리눅스 기반의 Docker를 이용해서 Openshift를 시작하는 방법은 다음과 같습니다: 141 | 142 | 143 | ``` 144 | docker rm origin 145 | sudo docker run -d --name "origin" \ 146 | --privileged --pid=host --net=host \ 147 | -v /:/rootfs:ro -v /var/run:/var/run:rw -v /sys:/sys -v /var/lib/docker:/var/lib/docker:rw \ 148 | -v /var/lib/origin/openshift.local.volumes:/var/lib/origin/openshift.local.volumes \ 149 | openshift/origin start 150 | docker logs -f origin 151 | ``` 152 | 153 | 당신은 `oc` 명령어 툴도 필요합니다. Openshift 웹사이트에서 다운받을 수 있습니다. 154 | 155 | ### Openshift에 로그인 하기 156 | 157 | 구동이 되면 다음과 같은 명령어를 입력합니다. 158 | 159 | ``` 160 | oc login 161 | # credentials are admin / admin 162 | ``` 163 | 164 | 그리고 나서 웹브라우저로 https://0.0.0.0:8443 를 접속하세요. 인증서가 아마 올바르지 않다고 나오겠지만 무시하고 접속하세요. 아마 아래의 사진과 비슷한 페이지를 보게 될 것 입니다. 165 | 166 | ![Openshift login](img/openshift-login.png "The Openshift login page") 167 | 168 | ### Aggregation 예제 169 | 170 | 171 | **Step 1: 프로젝트 생성** 172 | 173 | 우선 당신은 Openshift 프로젝트를 생성해야 하고, 권한도 부여해야 합니다: 174 | 175 | ``` 176 | oc new-project vertx-microservice-example-aggregation-http 177 | oc policy add-role-to-user admin admin -n vertx-microservice-example-aggregation-http 178 | oc policy add-role-to-group view system:serviceaccounts -n vertx-microservice-example-aggregation-http 179 | ``` 180 | 181 | **절대로** 프로젝트 이름을 바꾸지 마세요, 어플리케이션의 설정이 오직 이 프로젝트 이름에서만 작동되게 되어 있습니다. 더 자세한 것은 아래에 있습니다. 182 | 183 | **마이크로서비스 구동** 184 | 185 | 우선 'aggregation-http' 디렉토리로 이동하세요. 그리고 각각의 프로젝트 (A, B, C, D)를 실행시키세요: 186 | 187 | ``` 188 | mvn clean package docker:build fabric8:json fabric8:apply -Popenshift 189 | ``` 190 | 191 | 마이크로서비스를 포함하고 있는 Docker 이미지를 생성하기 위해 Docker Maven 플러그인과 the Fabric8 Maven 플러그인을 사용하고 있습니다. 192 | 이것은 Docker registry에 보내질 것이고, Openshift 어플리케이션을 생성할 것 입니다.(Kubernetes를 사용하는..) 193 | 194 | 만약 당신의 모든 컴포넌트들을 배포했다면, 당신은 아마 4개의 openshift pod를 가지고 있을 것 입니다. 각각은 하나의 서비스입니다: 195 | 196 | ![the Openshift pod and service list](img/openshift-pods.png "The Openshift pod and service list") 197 | 198 | 어플리케이션 페이지에 접속하기 위해선 당신은 `A`의 아이피 주소를 알아야 합니다. 이 아이피를 알아내기 위해선 `A`를 클릭하고 오른쪽 패널에서 IP를 알아내세요. 199 | 200 | ![the Openshift pod and service list](img/openshift-pods.png "The Openshift pod and service list") 201 | 202 | 아이피를 알아내면 다음의 페이지를 여세요: http://$아이피/assets/index.html 203 | 204 | 여러분은 _로컬 실행모드_ 와 동일하게 어플리케이션을 사용할 수 있습니다. 그리고 다시 Openshift overview 페이지로 넘어가서 B, C, D의 서비스 pod를 스케일-다운 시키세요: 205 | 206 | ![scaling down a pod](img/openshift-scaling-down.png "Scaling down a pod") 207 | 208 | 어플리케이션을 재 사용하기 위해서, circuit breaker는 아마 실패를 감지하고 fallback를 사용 할 것 입니다. 만약에 없애버린 pod를 복구하면 209 | 다시 어플리케이션은 _정상_ 상태로 돌아옵니다. 210 | 211 | **Kubernetes 와 service discovery** 212 | 213 | Openshift에서 구동할 때, Kubernetes 서비스가 vert.x 의 discovery 서비스에 임포트 됩니다. 그래서 이들은 어플리케이션의 _정규_ 서비스로 다루어집니다. 214 | 215 | ### 파이프라인 예제 216 | 217 | **Step 1: 프로젝트 생성** 218 | 219 | 우선 당신은 Openshift 프로젝트를 생성해야 하고, 권한도 부여해야 합니다: 220 | 221 | ``` 222 | oc new-project vertx-microservice-example-pipeline-http 223 | oc policy add-role-to-user admin admin -n vertx-microservice-example-pipeline-http 224 | oc policy add-role-to-group view system:serviceaccounts -n vertx-microservice-example-pipeline-http 225 | ``` 226 | 227 | **절대로** 프로젝트 이름을 바꾸지 마세요, 어플리케이션의 설정이 오직 이 프로젝트 이름에서만 작동되게 되어 있습니다. 더 자세한 것은 아래에 있습니다. 228 | 229 | **마이크로서비스 구동** 230 | 231 | 우선 `pipeline-http` 디렉토리로 이동하세요. 그리고 A, B, C, D 각각의 프로젝트를 구동시키세요. 232 | 233 | ``` 234 | mvn clean package docker:build fabric8:json fabric8:apply -Popenshift 235 | ``` 236 | 237 | 마이크로서비스를 포함하고 있는 Docker 이미지를 생성하기 위해 Docker Maven 플러그인과 the Fabric8 Maven 플러그인을 사용하고 있습니다. 238 | 이것은 Docker registry에 보내질 것이고, Openshift 어플리케이션을 생성할 것 입니다.(Kubernetes를 사용하는..) 239 | 240 | 만약 당신의 모든 컴포넌트들을 배포했다면, 당신은 아마 4개의 openshift pod를 가지고 있을 것 입니다. 각각은 하나의 서비스입니다: 241 | 242 | ![the Openshift pod and service list](img/openshift-pods.png "The Openshift pod and service list") 243 | 244 | 어플리케이션 페이지에 접속하기 위해선 당신은 `A`의 아이피 주소를 알아야 합니다. 이 아이피를 알아내기 위해선 `A`를 클릭하고 오른쪽 패널에서 IP를 알아내세요. 245 | 246 | ![the Openshift pod and service list](img/openshift-pods.png "The Openshift pod and service list") 247 | 248 | 아이피를 알아내면 다음의 페이지를 여세요: http://$아이피/assets/index.html 249 | 250 | 여러분은 _로컬 실행모드_ 와 동일하게 어플리케이션을 사용할 수 있습니다. 그리고 다시 Openshift overview 페이지로 넘어가서 B, C, D의 서비스 pod를 스케일-다운 시키세요: 251 | 252 | ![scaling down a pod](img/openshift-scaling-down.png "Scaling down a pod") 253 | 254 | 어플리케이션을 재 사용하기 위해서, circuit breaker는 아마 실패를 감지하고 fallback를 사용 할 것 입니다. 만약에 없애버린 pod를 복구하면 255 | 다시 어플리케이션은 _정상_ 상태로 돌아옵니다. 256 | 257 | 258 | ### 모든 서비스를 한번에 셧다운 시키는 방법 259 | 260 | Openshift 와 배포된 pod들을 종료시키기 위해선 다음의 명령어를 입력하세요: 261 | 262 | ``` 263 | # On bash 264 | docker stop `docker ps -qa` 265 | docker rm -f `docker ps -qa` 266 | # Fish 267 | docker stop (docker ps -qa) 268 | docker rm -f (docker ps -qa) 269 | ``` 270 | -------------------------------------------------------------------------------- /aggregation-http/A/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | aggregation-http 10 | 1.0-SNAPSHOT 11 | 12 | 13 | aggregation-http-a 14 | 15 | 16 | io.vertx.microservices.MainVerticle 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.4.3 25 | 26 | 27 | package 28 | 29 | shade 30 | 31 | 32 | 33 | 34 | 35 | io.vertx.core.Launcher 36 | ${main.verticle} 37 | 38 | 39 | 40 | META-INF/services/io.vertx.core.spi.VerticleFactory 41 | 42 | 43 | 44 | .SF 45 | .DSA 46 | 47 | 48 | 49 | 50 | 51 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | openshift 62 | 63 | a 64 | 80 65 | 8080 66 | LoadBalancer 67 | http-endpoint 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /aggregation-http/A/src/main/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8080 3 | } -------------------------------------------------------------------------------- /aggregation-http/A/src/main/java/io/vertx/microservices/A.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.CompositeFuture; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.Handler; 7 | import io.vertx.core.http.HttpClient; 8 | import io.vertx.core.json.JsonObject; 9 | import io.vertx.circuitbreaker.CircuitBreaker; 10 | import io.vertx.circuitbreaker.CircuitBreakerOptions; 11 | import io.vertx.servicediscovery.ServiceDiscovery; 12 | import io.vertx.servicediscovery.rest.ServiceDiscoveryRestEndpoint; 13 | import io.vertx.servicediscovery.types.HttpEndpoint; 14 | import io.vertx.ext.web.Router; 15 | import io.vertx.ext.web.RoutingContext; 16 | import io.vertx.ext.web.handler.StaticHandler; 17 | import io.vertx.ext.web.handler.sockjs.BridgeOptions; 18 | import io.vertx.ext.web.handler.sockjs.PermittedOptions; 19 | import io.vertx.ext.web.handler.sockjs.SockJSHandler; 20 | 21 | public class A extends AbstractVerticle { 22 | 23 | private ServiceDiscovery discovery; 24 | private CircuitBreaker circuitB, circuitC, circuitD; 25 | private HttpClient clientB, clientC, clientD; 26 | 27 | @Override 28 | public void start() throws Exception { 29 | Router router = Router.router(vertx); 30 | discovery = ServiceDiscovery.create(vertx); 31 | ServiceDiscoveryRestEndpoint.create(router, discovery); 32 | 33 | CircuitBreakerOptions options = new CircuitBreakerOptions() 34 | .setMaxFailures(2) 35 | .setTimeout(2000) 36 | .setResetTimeout(5000) 37 | .setFallbackOnFailure(true); 38 | 39 | circuitB = CircuitBreaker.create("B", vertx, options).openHandler(v -> { 40 | if (clientB != null) { 41 | clientB.close(); 42 | clientB = null; 43 | } 44 | }); 45 | circuitC = CircuitBreaker.create("C", vertx, options).openHandler(v -> { 46 | if (clientC != null) { 47 | clientC.close(); 48 | clientC = null; 49 | } 50 | }); 51 | ; 52 | circuitD = CircuitBreaker.create("D", vertx, options).openHandler(v -> { 53 | if (clientD != null) { 54 | clientD.close(); 55 | clientD = null; 56 | } 57 | }); 58 | ; 59 | 60 | router.route("/assets/*").handler(StaticHandler.create("assets")); 61 | router.get("/A").handler(this::hello); 62 | setupSockJsBridge(router); 63 | 64 | vertx.createHttpServer() 65 | .requestHandler(router::accept) 66 | .listen(config().getInteger("port")); 67 | } 68 | 69 | private void hello(RoutingContext context) { 70 | String param = context.request().getParam("name"); 71 | 72 | Future b = Future.future(); 73 | Future c = Future.future(); 74 | Future d = Future.future(); 75 | 76 | getB(client -> { 77 | invoke("B", client, circuitB, param, b); 78 | }); 79 | 80 | getC(client -> { 81 | invoke("C", client, circuitC, param, c); 82 | }); 83 | 84 | getD(client -> { 85 | invoke("D", client, circuitD, param, d); 86 | }); 87 | 88 | CompositeFuture.all(b, c, d).setHandler(ar -> { 89 | JsonObject result = new JsonObject(); 90 | result 91 | .put("A", "Hello " + param) 92 | .put("B", b.result()) 93 | .put("C", c.result()) 94 | .put("D", d.result()); 95 | 96 | context.response().putHeader("content-type", "application/json").end(result.encodePrettily()); 97 | }); 98 | } 99 | 100 | private void getB(Handler next) { 101 | if (clientB != null) { 102 | next.handle(clientB); 103 | } else { 104 | HttpEndpoint.getClient(discovery, new JsonObject().put("name", "B"), ar -> { 105 | clientB = ar.result(); 106 | next.handle(clientB); 107 | }); 108 | } 109 | } 110 | 111 | private void getD(Handler next) { 112 | if (clientD != null) { 113 | next.handle(clientD); 114 | } else { 115 | HttpEndpoint.getClient(discovery, new JsonObject().put("name", "D"), ar -> { 116 | clientD = ar.result(); 117 | next.handle(clientD); 118 | }); 119 | } 120 | } 121 | 122 | private void getC(Handler next) { 123 | if (clientC != null) { 124 | next.handle(clientC); 125 | } else { 126 | HttpEndpoint.getClient(discovery, new JsonObject().put("name", "C"), ar -> { 127 | clientC = ar.result(); 128 | next.handle(clientC); 129 | }); 130 | } 131 | } 132 | 133 | private void invoke(String name, HttpClient client, CircuitBreaker circuit, String param, Future future) { 134 | circuit.executeWithFallback( 135 | circuitFuture -> { 136 | if (client == null) { 137 | circuitFuture.fail("No service available"); 138 | } else { 139 | client.get("/?name=" + param, response -> { 140 | response.bodyHandler(buffer -> { 141 | future.complete(buffer.toJsonObject().getString(name)); 142 | circuitFuture.complete(); 143 | }); 144 | }).exceptionHandler(circuitFuture::fail) 145 | .end(); 146 | } 147 | }, 148 | v -> { 149 | // the future has already been completed, a failure or timeout. 150 | if (!future.isComplete()) future.complete("No service available (fallback)"); 151 | return null; 152 | } 153 | ); 154 | } 155 | 156 | private void setupSockJsBridge(Router router) { 157 | SockJSHandler sockJSHandler = SockJSHandler.create(vertx); 158 | BridgeOptions options = new BridgeOptions() 159 | .addOutboundPermitted( 160 | new PermittedOptions().setAddress("vertx.circuit-breaker")) 161 | .addInboundPermitted( 162 | new PermittedOptions().setAddress("vertx.circuit-breaker")); 163 | sockJSHandler.bridge(options); 164 | router.route("/eventbus/*").handler(sockJSHandler); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /aggregation-http/A/src/main/java/io/vertx/microservices/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.DeploymentOptions; 5 | 6 | 7 | public class MainVerticle extends AbstractVerticle { 8 | 9 | @Override 10 | public void start() throws Exception { 11 | DeploymentOptions options = new DeploymentOptions().setConfig(config()); 12 | vertx.deployVerticle(A.class.getName(), options); 13 | if (config().getBoolean("openshift", false)) { 14 | vertx.deployVerticle(OpenshiftVerticle.class.getName(), options); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /aggregation-http/A/src/main/java/io/vertx/microservices/OpenshiftVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.servicediscovery.ServiceDiscovery; 5 | import io.vertx.servicediscovery.kubernetes.KubernetesServiceImporter; 6 | 7 | /** 8 | * This verticle configure the Vert.x discovery to import services from Kubernetes. 9 | */ 10 | public class OpenshiftVerticle extends AbstractVerticle { 11 | 12 | private ServiceDiscovery discovery; 13 | 14 | @Override 15 | public void start() throws Exception { 16 | discovery = ServiceDiscovery 17 | .create(vertx) 18 | .registerServiceImporter(new KubernetesServiceImporter(), config()); 19 | } 20 | 21 | @Override 22 | public void stop() throws Exception { 23 | discovery.close(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /aggregation-http/A/src/main/resources/assets/circuits.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Circuit Breakers 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 |
16 |

Circuit Breakers

17 |
18 |
19 | 20 |
21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
NameStatusFailures
34 |
35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /aggregation-http/A/src/main/resources/assets/discovery.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Discovery 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 |
16 |

Services

17 |
18 |
19 | 20 |
21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
NameStatusRegistration IdLocationMetadata
36 |
37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /aggregation-http/A/src/main/resources/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Micro-Service Demo - ABCD - Browser Aggregation - HTTP 7 | 8 | 9 | 10 | 11 | 21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 |
29 |

Vert.x Micro-Services Sample - ABCD - Aggregation - HTTP

30 |

In this sample, this page is consuming 1 service using Ajax and print the result below. This service (A) calls 3 services (B, C and D) and builds an aggregated response. Enter a parameter in the text box and click on invoke. You can have 31 | a look to the circuit breakers using the circuit breaker status page. The available services are listed on the discovery page.

32 |
33 |
34 | 35 |
36 |
37 |
38 | 39 | 40 |
41 | 42 |
43 |
44 | 45 |

Result:

46 |
47 |
48 | 49 |
50 | 51 | 52 | 53 | 54 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /aggregation-http/A/src/main/resources/assets/libs/vertx-eventbus.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2015 The original author or authors 3 | * ------------------------------------------------------ 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * and Apache License v2.0 which accompanies this distribution. 7 | * 8 | * The Eclipse Public License is available at 9 | * http://www.eclipse.org/legal/epl-v10.html 10 | * 11 | * The Apache License v2.0 is available at 12 | * http://www.opensource.org/licenses/apache2.0.php 13 | * 14 | * You may elect to redistribute this code under either of these licenses. 15 | */ 16 | !function (factory) { 17 | if (typeof require === 'function' && typeof module !== 'undefined') { 18 | // CommonJS loader 19 | var SockJS = require('sockjs-client'); 20 | if(!SockJS) { 21 | throw new Error('vertx-eventbus.js requires sockjs-client, see http://sockjs.org'); 22 | } 23 | factory(SockJS); 24 | } else if (typeof define === 'function' && define.amd) { 25 | // AMD loader 26 | define('vertx-eventbus', ['sockjs'], factory); 27 | } else { 28 | // plain old include 29 | if (typeof this.SockJS === 'undefined') { 30 | throw new Error('vertx-eventbus.js requires sockjs-client, see http://sockjs.org'); 31 | } 32 | 33 | EventBus = factory(this.SockJS); 34 | } 35 | }(function (SockJS) { 36 | 37 | function makeUUID() { 38 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (a, b) { 39 | return b = Math.random() * 16, (a == 'y' ? b & 3 | 8 : b | 0).toString(16); 40 | }); 41 | } 42 | 43 | function mergeHeaders(defaultHeaders, headers) { 44 | if (defaultHeaders) { 45 | if(!headers) { 46 | return defaultHeaders; 47 | } 48 | 49 | for (var headerName in defaultHeaders) { 50 | if (defaultHeaders.hasOwnProperty(headerName)) { 51 | // user can overwrite the default headers 52 | if (typeof headers[headerName] === 'undefined') { 53 | headers[headerName] = defaultHeaders[headerName]; 54 | } 55 | } 56 | } 57 | } 58 | 59 | // headers are required to be a object 60 | return headers || {}; 61 | } 62 | 63 | /** 64 | * EventBus 65 | * 66 | * @param url 67 | * @param options 68 | * @constructor 69 | */ 70 | var EventBus = function (url, options) { 71 | var self = this; 72 | 73 | options = options || {}; 74 | 75 | var pingInterval = options.vertxbus_ping_interval || 5000; 76 | var pingTimerID; 77 | 78 | // attributes 79 | this.sockJSConn = new SockJS(url, null, options); 80 | this.state = EventBus.CONNECTING; 81 | this.handlers = {}; 82 | this.replyHandlers = {}; 83 | this.defaultHeaders = null; 84 | 85 | // default event handlers 86 | this.onerror = function (err) { 87 | try { 88 | console.error(err); 89 | } catch (e) { 90 | // dev tools are disabled so we cannot use console on IE 91 | } 92 | }; 93 | 94 | var sendPing = function () { 95 | self.sockJSConn.send(JSON.stringify({type: 'ping'})); 96 | }; 97 | 98 | this.sockJSConn.onopen = function () { 99 | // Send the first ping then send a ping every pingInterval milliseconds 100 | sendPing(); 101 | pingTimerID = setInterval(sendPing, pingInterval); 102 | self.state = EventBus.OPEN; 103 | self.onopen && self.onopen(); 104 | }; 105 | 106 | this.sockJSConn.onclose = function () { 107 | self.state = EventBus.CLOSED; 108 | if (pingTimerID) clearInterval(pingTimerID); 109 | self.onclose && self.onclose(); 110 | }; 111 | 112 | this.sockJSConn.onmessage = function (e) { 113 | var json = JSON.parse(e.data); 114 | 115 | // define a reply function on the message itself 116 | if (json.replyAddress) { 117 | Object.defineProperty(json, 'reply', { 118 | value: function (message, headers, callback) { 119 | self.send(json.replyAddress, message, headers, callback); 120 | } 121 | }); 122 | } 123 | 124 | if (self.handlers[json.address]) { 125 | // iterate all registered handlers 126 | var handlers = self.handlers[json.address]; 127 | for (var i = 0; i < handlers.length; i++) { 128 | if (json.type === 'err') { 129 | handlers[i]({failureCode: json.failureCode, failureType: json.failureType, message: json.message}); 130 | } else { 131 | handlers[i](null, json); 132 | } 133 | } 134 | } else if (self.replyHandlers[json.address]) { 135 | // Might be a reply message 136 | var handler = self.replyHandlers[json.address]; 137 | delete self.replyHandlers[json.address]; 138 | if (json.type === 'err') { 139 | handler({failureCode: json.failureCode, failureType: json.failureType, message: json.message}); 140 | } else { 141 | handler(null, json); 142 | } 143 | } else { 144 | if (json.type === 'err') { 145 | self.onerror(json); 146 | } else { 147 | try { 148 | console.warn('No handler found for message: ', json); 149 | } catch (e) { 150 | // dev tools are disabled so we cannot use console on IE 151 | } 152 | } 153 | } 154 | } 155 | }; 156 | 157 | /** 158 | * Send a message 159 | * 160 | * @param {String} address 161 | * @param {Object} message 162 | * @param {Object} [headers] 163 | * @param {Function} [callback] 164 | */ 165 | EventBus.prototype.send = function (address, message, headers, callback) { 166 | // are we ready? 167 | if (this.state != EventBus.OPEN) { 168 | throw new Error('INVALID_STATE_ERR'); 169 | } 170 | 171 | if (typeof headers === 'function') { 172 | callback = headers; 173 | headers = {}; 174 | } 175 | 176 | var envelope = { 177 | type: 'send', 178 | address: address, 179 | headers: mergeHeaders(this.defaultHeaders, headers), 180 | body: message 181 | }; 182 | 183 | if (callback) { 184 | var replyAddress = makeUUID(); 185 | envelope.replyAddress = replyAddress; 186 | this.replyHandlers[replyAddress] = callback; 187 | } 188 | 189 | this.sockJSConn.send(JSON.stringify(envelope)); 190 | }; 191 | 192 | /** 193 | * Publish a message 194 | * 195 | * @param {String} address 196 | * @param {Object} message 197 | * @param {Object} [headers] 198 | */ 199 | EventBus.prototype.publish = function (address, message, headers) { 200 | // are we ready? 201 | if (this.state != EventBus.OPEN) { 202 | throw new Error('INVALID_STATE_ERR'); 203 | } 204 | 205 | this.sockJSConn.send(JSON.stringify({ 206 | type: 'publish', 207 | address: address, 208 | headers: mergeHeaders(this.defaultHeaders, headers), 209 | body: message 210 | })); 211 | }; 212 | 213 | /** 214 | * Register a new handler 215 | * 216 | * @param {String} address 217 | * @param {Object} [headers] 218 | * @param {Function} callback 219 | */ 220 | EventBus.prototype.registerHandler = function (address, headers, callback) { 221 | // are we ready? 222 | if (this.state != EventBus.OPEN) { 223 | throw new Error('INVALID_STATE_ERR'); 224 | } 225 | 226 | if (typeof headers === 'function') { 227 | callback = headers; 228 | headers = {}; 229 | } 230 | 231 | // ensure it is an array 232 | if (!this.handlers[address]) { 233 | this.handlers[address] = []; 234 | // First handler for this address so we should register the connection 235 | this.sockJSConn.send(JSON.stringify({ 236 | type: 'register', 237 | address: address, 238 | headers: mergeHeaders(this.defaultHeaders, headers) 239 | })); 240 | } 241 | 242 | this.handlers[address].push(callback); 243 | }; 244 | 245 | /** 246 | * Unregister a handler 247 | * 248 | * @param {String} address 249 | * @param {Object} [headers] 250 | * @param {Function} callback 251 | */ 252 | EventBus.prototype.unregisterHandler = function (address, headers, callback) { 253 | // are we ready? 254 | if (this.state != EventBus.OPEN) { 255 | throw new Error('INVALID_STATE_ERR'); 256 | } 257 | 258 | var handlers = this.handlers[address]; 259 | 260 | if (handlers) { 261 | 262 | if (typeof headers === 'function') { 263 | callback = headers; 264 | headers = {}; 265 | } 266 | 267 | var idx = handlers.indexOf(callback); 268 | if (idx != -1) { 269 | handlers.splice(idx, 1); 270 | if (handlers.length === 0) { 271 | // No more local handlers so we should unregister the connection 272 | this.sockJSConn.send(JSON.stringify({ 273 | type: 'unregister', 274 | address: address, 275 | headers: mergeHeaders(this.defaultHeaders, headers) 276 | })); 277 | 278 | delete this.handlers[address]; 279 | } 280 | } 281 | } 282 | }; 283 | 284 | /** 285 | * Closes the connection to the EvenBus Bridge. 286 | */ 287 | EventBus.prototype.close = function () { 288 | this.state = EventBus.CLOSING; 289 | this.sockJSConn.close(); 290 | }; 291 | 292 | EventBus.CONNECTING = 0; 293 | EventBus.OPEN = 1; 294 | EventBus.CLOSING = 2; 295 | EventBus.CLOSED = 3; 296 | 297 | if (typeof exports !== 'undefined') { 298 | if (typeof module !== 'undefined' && module.exports) { 299 | exports = module.exports = EventBus; 300 | } else { 301 | exports.EventBus = EventBus; 302 | } 303 | } else { 304 | return EventBus; 305 | } 306 | }); -------------------------------------------------------------------------------- /aggregation-http/A/src/openshift/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port" : 8080, 3 | "openshift" : true, 4 | "namespace" : "vertx-microservice-example-aggregation-http" 5 | } -------------------------------------------------------------------------------- /aggregation-http/B/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | aggregation-http 10 | 1.0-SNAPSHOT 11 | 12 | 13 | aggregation-http-b 14 | 15 | 16 | io.vertx.microservices.MainVerticle 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.4.3 25 | 26 | 27 | package 28 | 29 | shade 30 | 31 | 32 | 33 | 34 | 35 | io.vertx.core.Launcher 36 | ${main.verticle} 37 | 38 | 39 | 40 | META-INF/services/io.vertx.core.spi.VerticleFactory 41 | 42 | 43 | 44 | 45 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | openshift 56 | 57 | b 58 | 80 59 | 8080 60 | LoadBalancer 61 | http-endpoint 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /aggregation-http/B/src/main/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8081 3 | } -------------------------------------------------------------------------------- /aggregation-http/B/src/main/java/io/vertx/microservices/B.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.json.JsonObject; 6 | import io.vertx.ext.web.Router; 7 | 8 | public class B extends AbstractVerticle { 9 | 10 | @Override 11 | public void start() throws Exception { 12 | Router router = Router.router(vertx); 13 | 14 | router.get("/").handler(context -> { 15 | String param = context.request().getParam("name"); 16 | context.response() 17 | .putHeader("content-type", "application/json") 18 | .end(new JsonObject().put("B", "Hola " + param).encodePrettily()); 19 | }); 20 | 21 | vertx.createHttpServer() 22 | .requestHandler(router::accept) 23 | .listen(config().getInteger("port")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /aggregation-http/B/src/main/java/io/vertx/microservices/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.DeploymentOptions; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.logging.Logger; 7 | import io.vertx.core.logging.LoggerFactory; 8 | import io.vertx.servicediscovery.ServiceDiscovery; 9 | import io.vertx.servicediscovery.Record; 10 | import io.vertx.servicediscovery.types.HttpEndpoint; 11 | 12 | 13 | public class MainVerticle extends AbstractVerticle { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(MainVerticle.class.getName()); 16 | 17 | private Record record; 18 | private ServiceDiscovery discovery; 19 | 20 | @Override 21 | public void start(Future future) throws Exception { 22 | DeploymentOptions options = new DeploymentOptions().setConfig(config()); 23 | vertx.deployVerticle(B.class.getName(), options); 24 | if (!config().getBoolean("openshift", false)) { 25 | discovery = ServiceDiscovery.create(vertx); 26 | publishService(future, discovery, "B"); 27 | } else { 28 | future.complete(); 29 | } 30 | } 31 | 32 | @Override 33 | public void stop(Future future) throws Exception { 34 | if (discovery != null && record != null) { 35 | discovery.unpublish(record.getRegistration(), ar -> { 36 | LOGGER.info("B has been un-published"); 37 | future.complete(); 38 | }); 39 | } else { 40 | future.complete(); 41 | } 42 | } 43 | 44 | private void publishService(Future future, ServiceDiscovery discovery, String name) { 45 | discovery.publish(HttpEndpoint.createRecord(name, "localhost", config().getInteger("port"), "/"), 46 | published -> { 47 | if (published.succeeded()) { 48 | this.record = published.result(); 49 | LOGGER.info(name + " has been published"); 50 | future.complete(); 51 | } else { 52 | future.fail("Cannot publish " + name + ": " + published.cause()); 53 | } 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /aggregation-http/B/src/openshift/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "openshift" : true, 3 | "port" : 8080 4 | } -------------------------------------------------------------------------------- /aggregation-http/C/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | aggregation-http 10 | 1.0-SNAPSHOT 11 | 12 | 13 | aggregation-http-c 14 | 15 | 16 | io.vertx.microservices.MainVerticle 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.4.3 25 | 26 | 27 | package 28 | 29 | shade 30 | 31 | 32 | 33 | 34 | 35 | io.vertx.core.Launcher 36 | ${main.verticle} 37 | 38 | 39 | 40 | META-INF/services/io.vertx.core.spi.VerticleFactory 41 | 42 | 43 | 44 | 45 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | openshift 56 | 57 | c 58 | 80 59 | 8080 60 | LoadBalancer 61 | http-endpoint 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /aggregation-http/C/src/main/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8082 3 | } -------------------------------------------------------------------------------- /aggregation-http/C/src/main/java/io/vertx/microservices/C.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.json.JsonObject; 6 | import io.vertx.ext.web.Router; 7 | 8 | public class C extends AbstractVerticle { 9 | 10 | @Override 11 | public void start() throws Exception { 12 | Router router = Router.router(vertx); 13 | 14 | router.get("/").handler(context -> { 15 | String param = context.request().getParam("name"); 16 | context.response() 17 | .putHeader("content-type", "application/json") 18 | .end(new JsonObject().put("C", "Olá " + param).encodePrettily()); 19 | }); 20 | 21 | vertx.createHttpServer() 22 | .requestHandler(router::accept) 23 | .listen(config().getInteger("port")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /aggregation-http/C/src/main/java/io/vertx/microservices/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.DeploymentOptions; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.logging.Logger; 7 | import io.vertx.core.logging.LoggerFactory; 8 | import io.vertx.servicediscovery.ServiceDiscovery; 9 | import io.vertx.servicediscovery.Record; 10 | import io.vertx.servicediscovery.types.HttpEndpoint; 11 | 12 | public class MainVerticle extends AbstractVerticle { 13 | 14 | private static final Logger LOGGER = LoggerFactory.getLogger(MainVerticle.class.getName()); 15 | 16 | private Record record; 17 | private ServiceDiscovery discovery; 18 | 19 | @Override 20 | public void start(Future future) throws Exception { 21 | DeploymentOptions options = new DeploymentOptions().setConfig(config()); 22 | vertx.deployVerticle(C.class.getName(), options); 23 | if (!config().getBoolean("openshift", false)) { 24 | discovery = ServiceDiscovery.create(vertx); 25 | publishService(future, discovery, "C"); 26 | } else { 27 | future.complete(); 28 | } 29 | } 30 | 31 | @Override 32 | public void stop(Future future) throws Exception { 33 | if (discovery != null && record != null) { 34 | discovery.unpublish(record.getRegistration(), ar -> { 35 | LOGGER.info("C has been un-published"); 36 | future.complete(); 37 | }); 38 | } else { 39 | future.complete(); 40 | } 41 | } 42 | 43 | private void publishService(Future future, ServiceDiscovery discovery, String name) { 44 | discovery.publish(HttpEndpoint.createRecord(name, "localhost", config().getInteger("port"), "/"), 45 | published -> { 46 | if (published.succeeded()) { 47 | this.record = published.result(); 48 | LOGGER.info(name + " has been published"); 49 | future.complete(); 50 | } else { 51 | future.fail("Cannot publish " + name + ": " + published.cause()); 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /aggregation-http/C/src/openshift/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "openshift" : true, 3 | "port" : 8080 4 | } -------------------------------------------------------------------------------- /aggregation-http/D/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | aggregation-http 10 | 1.0-SNAPSHOT 11 | 12 | 13 | aggregation-http-d 14 | 15 | 16 | io.vertx.microservices.MainVerticle 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.4.3 25 | 26 | 27 | package 28 | 29 | shade 30 | 31 | 32 | 33 | 34 | 35 | io.vertx.core.Launcher 36 | ${main.verticle} 37 | 38 | 39 | 40 | META-INF/services/io.vertx.core.spi.VerticleFactory 41 | 42 | 43 | 44 | 45 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | openshift 56 | 57 | d 58 | 80 59 | 8080 60 | LoadBalancer 61 | http-endpoint 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /aggregation-http/D/src/main/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8083 3 | } -------------------------------------------------------------------------------- /aggregation-http/D/src/main/java/io/vertx/microservices/D.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.json.JsonObject; 6 | import io.vertx.ext.web.Router; 7 | 8 | public class D extends AbstractVerticle { 9 | 10 | @Override 11 | public void start() throws Exception { 12 | Router router = Router.router(vertx); 13 | 14 | router.get("/").handler(context -> { 15 | String param = context.request().getParam("name"); 16 | context.response() 17 | .putHeader("content-type", "application/json") 18 | .end(new JsonObject().put("D", "Aloha " + param).encodePrettily()); 19 | }); 20 | 21 | vertx.createHttpServer() 22 | .requestHandler(router::accept) 23 | .listen(config().getInteger("port")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /aggregation-http/D/src/main/java/io/vertx/microservices/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.DeploymentOptions; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.logging.Logger; 7 | import io.vertx.core.logging.LoggerFactory; 8 | import io.vertx.servicediscovery.ServiceDiscovery; 9 | import io.vertx.servicediscovery.Record; 10 | import io.vertx.servicediscovery.types.HttpEndpoint; 11 | 12 | 13 | public class MainVerticle extends AbstractVerticle { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(MainVerticle.class.getName()); 16 | 17 | private Record record; 18 | private ServiceDiscovery discovery; 19 | 20 | @Override 21 | public void start(Future future) throws Exception { 22 | DeploymentOptions options = new DeploymentOptions().setConfig(config()); 23 | vertx.deployVerticle(D.class.getName(), options); 24 | if (!config().getBoolean("openshift", false)) { 25 | discovery = ServiceDiscovery.create(vertx); 26 | publishService(future, discovery, "D"); 27 | } else { 28 | future.complete(); 29 | } 30 | } 31 | 32 | @Override 33 | public void stop(Future future) throws Exception { 34 | if (discovery != null && record != null) { 35 | discovery.unpublish(record.getRegistration(), ar -> { 36 | LOGGER.info("D has been un-published"); 37 | future.complete(); 38 | }); 39 | } else { 40 | future.complete(); 41 | } 42 | } 43 | 44 | private void publishService(Future future, ServiceDiscovery discovery, String name) { 45 | discovery.publish(HttpEndpoint.createRecord(name, "localhost", config().getInteger("port"), "/"), 46 | published -> { 47 | if (published.succeeded()) { 48 | this.record = published.result(); 49 | LOGGER.info(name + " has been published"); 50 | future.complete(); 51 | } else { 52 | future.fail("Cannot publish " + name + ": " + published.cause()); 53 | } 54 | }); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /aggregation-http/D/src/openshift/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "openshift" : true, 3 | "port" : 8080 4 | } -------------------------------------------------------------------------------- /aggregation-http/etc/cluster.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | false 7 | false 8 | false 9 | 0 10 | jdk 11 | 12 | 13 | 14 | 5701 15 | 16 | 0 17 | 18 | 19 | 20 | 224.2.2.3 21 | 54327 22 | 23 | 24 | 127.0.0.1 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 41 | PBEWithMD5AndDES 42 | 43 | thesalt 44 | 45 | thepass 46 | 47 | 19 48 | 49 | 50 | 51 | 52 | 16 53 | 54 | 0 55 | 56 | 57 | 58 | 63 | 1 64 | 70 | 0 71 | 77 | 0 78 | 85 | NONE 86 | 92 | 0 93 | 99 | 25 100 | 115 | com.hazelcast.map.merge.LatestUpdateMapMergePolicy 116 | 117 | 118 | 119 | 120 | 121 | 1 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /aggregation-http/etc/vertx-eventbus-service.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion" : "v1", 3 | "kind": "Service", 4 | "metadata" : { 5 | "name" : "vertx-eventbus" 6 | }, 7 | "spec" : { 8 | "clusterIP": "None", 9 | "type" : "ClusterIP", 10 | "selector" : { 11 | "vertx-cluster": "true" 12 | }, 13 | "ports": [{ 14 | "port": 5701, 15 | "protocol" : "TCP" 16 | }] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /aggregation-http/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | samples 10 | 1.0-SNAPSHOT 11 | 12 | 13 | aggregation-http 14 | 15 | pom 16 | 17 | 18 | 19 | io.vertx 20 | vertx-service-discovery-bridge-kubernetes 21 | ${vertx.version} 22 | 23 | 24 | 25 | 26 | A 27 | B 28 | C 29 | D 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /img/aggregation-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cescoffier/vertx-microservices-examples/811c2dabe6fc7078b34504f42a4160c926a0d0f2/img/aggregation-page.png -------------------------------------------------------------------------------- /img/get-service-ip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cescoffier/vertx-microservices-examples/811c2dabe6fc7078b34504f42a4160c926a0d0f2/img/get-service-ip.png -------------------------------------------------------------------------------- /img/openshift-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cescoffier/vertx-microservices-examples/811c2dabe6fc7078b34504f42a4160c926a0d0f2/img/openshift-login.png -------------------------------------------------------------------------------- /img/openshift-pods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cescoffier/vertx-microservices-examples/811c2dabe6fc7078b34504f42a4160c926a0d0f2/img/openshift-pods.png -------------------------------------------------------------------------------- /img/openshift-scaling-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cescoffier/vertx-microservices-examples/811c2dabe6fc7078b34504f42a4160c926a0d0f2/img/openshift-scaling-down.png -------------------------------------------------------------------------------- /img/pipeline-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cescoffier/vertx-microservices-examples/811c2dabe6fc7078b34504f42a4160c926a0d0f2/img/pipeline-page.png -------------------------------------------------------------------------------- /pipeline-http/A/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | pipeline-http 10 | 1.0-SNAPSHOT 11 | 12 | 13 | pipeline-http-a 14 | 15 | 16 | io.vertx.microservices.MainVerticle 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.4.3 25 | 26 | 27 | package 28 | 29 | shade 30 | 31 | 32 | 33 | 34 | 35 | io.vertx.core.Launcher 36 | ${main.verticle} 37 | 38 | 39 | 40 | META-INF/services/io.vertx.core.spi.VerticleFactory 41 | 42 | 43 | 44 | 45 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | openshift 56 | 57 | a 58 | 80 59 | 8080 60 | LoadBalancer 61 | http-endpoint 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /pipeline-http/A/src/main/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8080 3 | } -------------------------------------------------------------------------------- /pipeline-http/A/src/main/java/io/vertx/microservices/A.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.Handler; 5 | import io.vertx.core.buffer.Buffer; 6 | import io.vertx.core.http.HttpClient; 7 | import io.vertx.core.json.JsonObject; 8 | import io.vertx.circuitbreaker.CircuitBreaker; 9 | import io.vertx.circuitbreaker.CircuitBreakerOptions; 10 | import io.vertx.servicediscovery.ServiceDiscovery; 11 | import io.vertx.servicediscovery.rest.ServiceDiscoveryRestEndpoint; 12 | import io.vertx.servicediscovery.types.HttpEndpoint; 13 | import io.vertx.ext.web.Router; 14 | import io.vertx.ext.web.RoutingContext; 15 | import io.vertx.ext.web.handler.StaticHandler; 16 | 17 | public class A extends AbstractVerticle { 18 | 19 | private ServiceDiscovery discovery; 20 | private CircuitBreaker circuit; 21 | private HttpClient client; 22 | 23 | @Override 24 | public void start() throws Exception { 25 | Router router = Router.router(vertx); 26 | discovery = ServiceDiscovery.create(vertx); 27 | 28 | circuit = CircuitBreaker.create("A", vertx, 29 | new CircuitBreakerOptions() 30 | .setMaxFailures(1) 31 | .setTimeout(3000) 32 | .setResetTimeout(5000) 33 | .setFallbackOnFailure(true)) 34 | .halfOpenHandler(v -> { 35 | if (client != null) { 36 | client.close(); 37 | client = null; 38 | } 39 | }); 40 | 41 | router.route("/assets/*").handler(StaticHandler.create("assets")); 42 | router.get("/A").handler(this::hello); 43 | ServiceDiscoveryRestEndpoint.create(router, discovery); 44 | 45 | vertx.createHttpServer() 46 | .requestHandler(router::accept) 47 | .listen(config().getInteger("port")); 48 | } 49 | 50 | private void hello(RoutingContext context) { 51 | getClient(client -> invokeAndReply(client, context)); 52 | } 53 | 54 | private void invokeAndReply(HttpClient client, RoutingContext context) { 55 | String param = context.request().getParam("name"); 56 | if (client == null) { 57 | // No record - fallback 58 | fallback(context, param); 59 | } else { 60 | circuit.executeWithFallback( 61 | future -> 62 | client.get("/?name=" + param, response -> { 63 | response.bodyHandler(buffer -> buildResponse(context, param, buffer)); 64 | future.complete(); 65 | }) 66 | .exceptionHandler(future::fail) 67 | .end() 68 | , 69 | v -> { 70 | fallback(context, param); 71 | return null; 72 | } 73 | ); 74 | } 75 | } 76 | 77 | private void getClient(Handler resultHandler) { 78 | if (client != null) { 79 | resultHandler.handle(client); 80 | } else { 81 | HttpEndpoint.getClient(discovery, new JsonObject().put("name", "B"), ar -> { 82 | resultHandler.handle(ar.result()); 83 | }); 84 | } 85 | } 86 | 87 | private void buildResponse(RoutingContext context, String param, Buffer buffer) { 88 | context.response() 89 | .putHeader("content-type", "application/json") 90 | .end(buffer.toJsonObject().put("A", "Hello " + param).encodePrettily()); 91 | } 92 | 93 | private void fallback(RoutingContext context, String param) { 94 | context.response() 95 | .putHeader("content-type", "application/json") 96 | .end(new JsonObject() 97 | .put("B", "No service available (fallback)") 98 | .put("A", "Hello " + param).encodePrettily()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /pipeline-http/A/src/main/java/io/vertx/microservices/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.DeploymentOptions; 5 | 6 | 7 | public class MainVerticle extends AbstractVerticle { 8 | 9 | @Override 10 | public void start() throws Exception { 11 | DeploymentOptions options = new DeploymentOptions().setConfig(config()); 12 | vertx.deployVerticle(A.class.getName(), options); 13 | if (config().getBoolean("openshift", false)) { 14 | vertx.deployVerticle(OpenshiftVerticle.class.getName(), options); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pipeline-http/A/src/main/java/io/vertx/microservices/OpenshiftVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.servicediscovery.ServiceDiscovery; 5 | import io.vertx.servicediscovery.kubernetes.KubernetesServiceImporter; 6 | /** 7 | * This verticle configure the Vert.x discovery to import services from Kubernetes. 8 | */ 9 | public class OpenshiftVerticle extends AbstractVerticle { 10 | 11 | private ServiceDiscovery discovery; 12 | 13 | @Override 14 | public void start() throws Exception { 15 | discovery = ServiceDiscovery 16 | .create(vertx) 17 | .registerServiceImporter(new KubernetesServiceImporter(), config()); 18 | } 19 | 20 | @Override 21 | public void stop() throws Exception { 22 | discovery.close(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pipeline-http/A/src/main/resources/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Micro-Service Demo - ABCD - Browser Aggregation - HTTP 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 |
24 | 25 |
26 |
27 |

Vert.x Micro-Services Sample - ABCD - Pipeline - HTTP

28 |

In this sample, this page is consuming 1 service using Ajax and print the result below. This service calls another service (B), calling another one (C), which call a final one (D). 29 | Enter a parameter in the text box and click on invoke.

30 |
31 |
32 | 33 |
34 |
35 |
36 | 37 | 38 |
39 | 40 |
41 |
42 | 43 |

Result:

44 |
45 |
46 | 47 |
48 | 49 | 52 | 53 | 54 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /pipeline-http/A/src/openshift/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8080, 3 | "openshift": true, 4 | "namespace": "vertx-microservice-example-pipeline-http" 5 | } -------------------------------------------------------------------------------- /pipeline-http/B/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | pipeline-http 10 | 1.0-SNAPSHOT 11 | 12 | 13 | pipeline-http-b 14 | 15 | 16 | io.vertx.microservices.MainVerticle 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.4.3 25 | 26 | 27 | package 28 | 29 | shade 30 | 31 | 32 | 33 | 34 | 35 | io.vertx.core.Launcher 36 | ${main.verticle} 37 | 38 | 39 | 40 | META-INF/services/io.vertx.core.spi.VerticleFactory 41 | 42 | 43 | 44 | 45 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | openshift 56 | 57 | b 58 | 80 59 | 8080 60 | LoadBalancer 61 | http-endpoint 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /pipeline-http/B/src/main/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8081 3 | } -------------------------------------------------------------------------------- /pipeline-http/B/src/main/java/io/vertx/microservices/B.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.buffer.Buffer; 7 | import io.vertx.core.http.HttpClient; 8 | import io.vertx.core.json.JsonObject; 9 | import io.vertx.core.logging.Logger; 10 | import io.vertx.core.logging.LoggerFactory; 11 | import io.vertx.circuitbreaker.CircuitBreaker; 12 | import io.vertx.circuitbreaker.CircuitBreakerOptions; 13 | import io.vertx.servicediscovery.ServiceDiscovery; 14 | import io.vertx.servicediscovery.types.HttpEndpoint; 15 | import io.vertx.ext.web.Router; 16 | import io.vertx.ext.web.RoutingContext; 17 | 18 | public class B extends AbstractVerticle { 19 | 20 | private final static Logger LOGGER = LoggerFactory.getLogger(B.class); 21 | private ServiceDiscovery discovery; 22 | private CircuitBreaker circuit; 23 | private HttpClient client; 24 | 25 | @Override 26 | public void start() throws Exception { 27 | Router router = Router.router(vertx); 28 | discovery = ServiceDiscovery.create(vertx); 29 | circuit = CircuitBreaker.create("B", vertx, 30 | new CircuitBreakerOptions() 31 | .setMaxFailures(1) 32 | .setTimeout(3000) 33 | .setResetTimeout(5000) 34 | .setFallbackOnFailure(true)) 35 | .halfOpenHandler(v -> { 36 | if (client != null) { 37 | client.close(); 38 | client = null; 39 | } 40 | }); 41 | 42 | router.get("/").handler(this::hello); 43 | 44 | vertx.createHttpServer() 45 | .requestHandler(router::accept) 46 | .listen(config().getInteger("port")); 47 | } 48 | 49 | @Override 50 | public void stop() throws Exception { 51 | if (client != null) { 52 | client.close(); 53 | } 54 | } 55 | 56 | private void hello(RoutingContext context) { 57 | getClient(client -> invokeAndReply(client, context)); 58 | } 59 | 60 | private void invokeAndReply(HttpClient client, RoutingContext context) { 61 | String param = context.request().getParam("name"); 62 | if (client == null) { 63 | // No record - fallback 64 | fallback(context, param); 65 | } else { 66 | circuit.executeWithFallback( 67 | future -> 68 | client.get("/?name=" + param, response -> { 69 | response.bodyHandler(buffer -> buildResponse(context, param, buffer)); 70 | future.complete(); 71 | }) 72 | .exceptionHandler(future::fail) 73 | .end() 74 | , 75 | v -> { 76 | fallback(context, param); 77 | return null; 78 | } 79 | ); 80 | } 81 | } 82 | 83 | private void getClient(Handler resultHandler) { 84 | if (client != null) { 85 | resultHandler.handle(client); 86 | } else { 87 | HttpEndpoint.getClient(discovery, new JsonObject().put("name", "C"), ar -> { 88 | if (ar.failed()) { 89 | LOGGER.info("Service lookup failure", ar.cause()); 90 | } 91 | client = ar.result(); 92 | resultHandler.handle(client); 93 | }); 94 | } 95 | } 96 | 97 | private void buildResponse(RoutingContext context, String param, Buffer buffer) { 98 | context.response() 99 | .putHeader("content-type", "application/json") 100 | .end(buffer.toJsonObject().put("B", "Hola " + param).encodePrettily()); 101 | } 102 | 103 | private void fallback(RoutingContext context, String param) { 104 | context.response() 105 | .putHeader("content-type", "application/json") 106 | .end(new JsonObject() 107 | .put("C", "No service available (fallback)") 108 | .put("B", "Hola " + param).encodePrettily()); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /pipeline-http/B/src/main/java/io/vertx/microservices/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.DeploymentOptions; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.logging.Logger; 7 | import io.vertx.core.logging.LoggerFactory; 8 | import io.vertx.servicediscovery.ServiceDiscovery; 9 | import io.vertx.servicediscovery.Record; 10 | import io.vertx.servicediscovery.types.HttpEndpoint; 11 | 12 | 13 | public class MainVerticle extends AbstractVerticle { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(MainVerticle.class.getName()); 16 | 17 | private Record record; 18 | private ServiceDiscovery discovery; 19 | 20 | @Override 21 | public void start(Future future) throws Exception { 22 | DeploymentOptions options = new DeploymentOptions().setConfig(config()); 23 | vertx.deployVerticle(B.class.getName(), options); 24 | 25 | if (!config().getBoolean("openshift", false)) { 26 | discovery = ServiceDiscovery.create(vertx); 27 | publishService(future, discovery, "B"); 28 | } else { 29 | vertx.deployVerticle(OpenshiftVerticle.class.getName(), options); 30 | future.complete(); 31 | } 32 | } 33 | 34 | @Override 35 | public void stop(Future future) throws Exception { 36 | if (discovery != null && record != null) { 37 | discovery.unpublish(record.getRegistration(), ar -> { 38 | LOGGER.info("B has been un-published"); 39 | future.complete(); 40 | }); 41 | } else { 42 | future.complete(); 43 | } 44 | } 45 | 46 | private void publishService(Future future, ServiceDiscovery discovery, String name) { 47 | discovery.publish(HttpEndpoint.createRecord(name, "localhost", config().getInteger("port"), "/"), 48 | published -> { 49 | if (published.succeeded()) { 50 | this.record = published.result(); 51 | LOGGER.info(name + " has been published"); 52 | future.complete(); 53 | } else { 54 | future.fail("Cannot publish " + name + ": " + published.cause()); 55 | } 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pipeline-http/B/src/main/java/io/vertx/microservices/OpenshiftVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.servicediscovery.ServiceDiscovery; 5 | import io.vertx.servicediscovery.kubernetes.KubernetesServiceImporter; 6 | 7 | /** 8 | * This verticle configure the Vert.x discovery to import services from Kubernetes. 9 | */ 10 | public class OpenshiftVerticle extends AbstractVerticle { 11 | 12 | private ServiceDiscovery discovery; 13 | 14 | @Override 15 | public void start() throws Exception { 16 | discovery = ServiceDiscovery 17 | .create(vertx) 18 | .registerServiceImporter(new KubernetesServiceImporter(), config()); 19 | } 20 | 21 | @Override 22 | public void stop() throws Exception { 23 | discovery.close(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pipeline-http/B/src/openshift/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "openshift": true, 3 | "namespace": "vertx-microservice-example-pipeline-http", 4 | "port" : 8080 5 | } -------------------------------------------------------------------------------- /pipeline-http/C/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | pipeline-http 10 | 1.0-SNAPSHOT 11 | 12 | 13 | pipeline-http-c 14 | 15 | 16 | io.vertx.microservices.MainVerticle 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.4.3 25 | 26 | 27 | package 28 | 29 | shade 30 | 31 | 32 | 33 | 34 | 35 | io.vertx.core.Launcher 36 | ${main.verticle} 37 | 38 | 39 | 40 | META-INF/services/io.vertx.core.spi.VerticleFactory 41 | 42 | 43 | 44 | 45 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | openshift 56 | 57 | c 58 | 80 59 | 8080 60 | LoadBalancer 61 | http-endpoint 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /pipeline-http/C/src/main/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8082 3 | } -------------------------------------------------------------------------------- /pipeline-http/C/src/main/java/io/vertx/microservices/C.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.buffer.Buffer; 7 | import io.vertx.core.http.HttpClient; 8 | import io.vertx.core.json.JsonObject; 9 | import io.vertx.circuitbreaker.CircuitBreaker; 10 | import io.vertx.circuitbreaker.CircuitBreakerOptions; 11 | import io.vertx.servicediscovery.ServiceDiscovery; 12 | import io.vertx.servicediscovery.types.HttpEndpoint; 13 | import io.vertx.ext.web.Router; 14 | import io.vertx.ext.web.RoutingContext; 15 | 16 | public class C extends AbstractVerticle { 17 | 18 | private ServiceDiscovery discovery; 19 | private CircuitBreaker circuit; 20 | private HttpClient client; 21 | 22 | @Override 23 | public void start() throws Exception { 24 | Router router = Router.router(vertx); 25 | discovery = ServiceDiscovery.create(vertx); 26 | circuit = CircuitBreaker.create("C", vertx, 27 | new CircuitBreakerOptions() 28 | .setMaxFailures(1) 29 | .setTimeout(3000) 30 | .setResetTimeout(5000) 31 | .setFallbackOnFailure(true)) 32 | .halfOpenHandler(v -> { 33 | if (client != null) { 34 | client.close(); 35 | client = null; 36 | } 37 | }); 38 | 39 | router.get("/").handler(this::hello); 40 | 41 | vertx.createHttpServer() 42 | .requestHandler(router::accept) 43 | .listen(config().getInteger("port")); 44 | } 45 | 46 | @Override 47 | public void stop() throws Exception { 48 | if (client != null) { 49 | client.close(); 50 | } 51 | } 52 | 53 | private void hello(RoutingContext context) { 54 | getClient(client -> invokeAndReply(client, context)); 55 | } 56 | 57 | private void invokeAndReply(HttpClient client, RoutingContext context) { 58 | String param = context.request().getParam("name"); 59 | if (client == null) { 60 | // No record - fallback 61 | fallback(context, param); 62 | } else { 63 | circuit.executeWithFallback( 64 | future -> 65 | client.get("/?name=" + param, response -> { 66 | response.bodyHandler(buffer -> buildResponse(context, param, buffer)); 67 | future.complete(); 68 | }) 69 | .exceptionHandler(future::fail) 70 | .end() 71 | , 72 | v -> { 73 | fallback(context, param); 74 | return null; 75 | } 76 | ); 77 | } 78 | } 79 | 80 | private void getClient(Handler resultHandler) { 81 | if (client != null) { 82 | resultHandler.handle(client); 83 | } else { 84 | HttpEndpoint.getClient(discovery, new JsonObject().put("name", "D"), ar -> { 85 | client = ar.result(); 86 | resultHandler.handle(client); 87 | }); 88 | } 89 | } 90 | 91 | private void buildResponse(RoutingContext context, String param, Buffer buffer) { 92 | context.response() 93 | .putHeader("content-type", "application/json") 94 | .end(buffer.toJsonObject().put("C", "Olá " + param).encodePrettily()); 95 | } 96 | 97 | private void fallback(RoutingContext context, String param) { 98 | context.response() 99 | .putHeader("content-type", "application/json") 100 | .end(new JsonObject() 101 | .put("D", "No service available (fallback)") 102 | .put("C", "Olá " + param).encodePrettily()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /pipeline-http/C/src/main/java/io/vertx/microservices/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.DeploymentOptions; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.logging.Logger; 7 | import io.vertx.core.logging.LoggerFactory; 8 | import io.vertx.servicediscovery.ServiceDiscovery; 9 | import io.vertx.servicediscovery.Record; 10 | import io.vertx.servicediscovery.types.HttpEndpoint; 11 | 12 | 13 | public class MainVerticle extends AbstractVerticle { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(MainVerticle.class.getName()); 16 | 17 | private Record record; 18 | private ServiceDiscovery discovery; 19 | 20 | @Override 21 | public void start(Future future) throws Exception { 22 | DeploymentOptions options = new DeploymentOptions().setConfig(config()); 23 | vertx.deployVerticle(C.class.getName(), options); 24 | 25 | if (!config().getBoolean("openshift", false)) { 26 | discovery = ServiceDiscovery.create(vertx); 27 | publishService(future, discovery, "C"); 28 | } else { 29 | vertx.deployVerticle(OpenshiftVerticle.class.getName(), options); 30 | future.complete(); 31 | } 32 | } 33 | 34 | @Override 35 | public void stop(Future future) throws Exception { 36 | if (discovery != null && record != null) { 37 | discovery.unpublish(record.getRegistration(), ar -> { 38 | LOGGER.info("C has been un-published"); 39 | future.complete(); 40 | }); 41 | } else { 42 | future.complete(); 43 | } 44 | } 45 | 46 | private void publishService(Future future, ServiceDiscovery discovery, String name) { 47 | discovery.publish(HttpEndpoint.createRecord(name, "localhost", config().getInteger("port"), "/"), 48 | published -> { 49 | if (published.succeeded()) { 50 | this.record = published.result(); 51 | LOGGER.info(name + " has been published"); 52 | future.complete(); 53 | } else { 54 | future.fail("Cannot publish " + name + ": " + published.cause()); 55 | } 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pipeline-http/C/src/main/java/io/vertx/microservices/OpenshiftVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.servicediscovery.ServiceDiscovery; 5 | import io.vertx.servicediscovery.kubernetes.KubernetesServiceImporter; 6 | 7 | /** 8 | * This verticle configure the Vert.x discovery to import services from Kubernetes. 9 | */ 10 | public class OpenshiftVerticle extends AbstractVerticle { 11 | 12 | private ServiceDiscovery discovery; 13 | 14 | @Override 15 | public void start() throws Exception { 16 | discovery = ServiceDiscovery 17 | .create(vertx) 18 | .registerServiceImporter(new KubernetesServiceImporter(), config()); 19 | } 20 | 21 | @Override 22 | public void stop() throws Exception { 23 | discovery.close(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pipeline-http/C/src/openshift/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "openshift": true, 3 | "namespace": "vertx-microservice-example-pipeline-http", 4 | "port" : 8080 5 | } -------------------------------------------------------------------------------- /pipeline-http/D/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | pipeline-http 10 | 1.0-SNAPSHOT 11 | 12 | 13 | pipeline-http-d 14 | 15 | 16 | io.vertx.microservices.MainVerticle 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.4.3 25 | 26 | 27 | package 28 | 29 | shade 30 | 31 | 32 | 33 | 34 | 35 | io.vertx.core.Launcher 36 | ${main.verticle} 37 | 38 | 39 | 40 | META-INF/services/io.vertx.core.spi.VerticleFactory 41 | 42 | 43 | 44 | 45 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | openshift 58 | 59 | d 60 | 80 61 | 8080 62 | LoadBalancer 63 | http-endpoint 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /pipeline-http/D/src/main/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 8084 3 | } -------------------------------------------------------------------------------- /pipeline-http/D/src/main/java/io/vertx/microservices/D.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.json.JsonObject; 5 | import io.vertx.ext.web.Router; 6 | 7 | public class D extends AbstractVerticle { 8 | 9 | @Override 10 | public void start() throws Exception { 11 | Router router = Router.router(vertx); 12 | 13 | router.get("/").handler(context -> { 14 | String param = context.request().getParam("name"); 15 | context.response() 16 | .putHeader("content-type", "application/json") 17 | .end(new JsonObject().put("D", "Aloha " + param).encodePrettily()); 18 | }); 19 | 20 | vertx.createHttpServer() 21 | .requestHandler(router::accept) 22 | .listen(config().getInteger("port")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pipeline-http/D/src/main/java/io/vertx/microservices/MainVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.core.DeploymentOptions; 5 | import io.vertx.core.Future; 6 | import io.vertx.core.logging.Logger; 7 | import io.vertx.core.logging.LoggerFactory; 8 | import io.vertx.servicediscovery.ServiceDiscovery; 9 | import io.vertx.servicediscovery.Record; 10 | import io.vertx.servicediscovery.types.HttpEndpoint; 11 | 12 | 13 | public class MainVerticle extends AbstractVerticle { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(MainVerticle.class.getName()); 16 | 17 | private Record record; 18 | private ServiceDiscovery discovery; 19 | 20 | @Override 21 | public void start(Future future) throws Exception { 22 | DeploymentOptions options = new DeploymentOptions().setConfig(config()); 23 | vertx.deployVerticle(D.class.getName(), options); 24 | 25 | if (!config().getBoolean("openshift", false)) { 26 | discovery = ServiceDiscovery.create(vertx); 27 | publishService(future, discovery, "D"); 28 | } else { 29 | vertx.deployVerticle(OpenshiftVerticle.class.getName(), options); 30 | future.complete(); 31 | } 32 | } 33 | 34 | @Override 35 | public void stop(Future future) throws Exception { 36 | if (discovery != null && record != null) { 37 | discovery.unpublish(record.getRegistration(), ar -> { 38 | LOGGER.info("D has been un-published"); 39 | future.complete(); 40 | }); 41 | } else { 42 | future.complete(); 43 | } 44 | } 45 | 46 | private void publishService(Future future, ServiceDiscovery discovery, String name) { 47 | discovery.publish(HttpEndpoint.createRecord(name, "localhost", config().getInteger("port"), "/"), 48 | published -> { 49 | if (published.succeeded()) { 50 | this.record = published.result(); 51 | LOGGER.info(name + " has been published"); 52 | future.complete(); 53 | } else { 54 | future.fail("Cannot publish " + name + ": " + published.cause()); 55 | } 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pipeline-http/D/src/main/java/io/vertx/microservices/OpenshiftVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.microservices; 2 | 3 | import io.vertx.core.AbstractVerticle; 4 | import io.vertx.servicediscovery.ServiceDiscovery; 5 | import io.vertx.servicediscovery.kubernetes.KubernetesServiceImporter; 6 | 7 | /** 8 | * This verticle configure the Vert.x discovery to import services from Kubernetes. 9 | */ 10 | public class OpenshiftVerticle extends AbstractVerticle { 11 | 12 | private ServiceDiscovery discovery; 13 | 14 | @Override 15 | public void start() throws Exception { 16 | discovery = ServiceDiscovery 17 | .create(vertx) 18 | .registerServiceImporter(new KubernetesServiceImporter(), config()); 19 | } 20 | 21 | @Override 22 | public void stop() throws Exception { 23 | discovery.close(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pipeline-http/D/src/openshift/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "openshift": true, 3 | "namespace": "vertx-microservice-example-pipeline-http", 4 | "port" : 8080 5 | } -------------------------------------------------------------------------------- /pipeline-http/README.md: -------------------------------------------------------------------------------- 1 | # Microservice - Pipeline - HTTP 2 | 3 | This demo illustrates the pipeline pattern (a service calling another service, calling another service). 4 | 5 | The demo is composed by four services: A -> B -> C -> D. All services are exposing a simple REST API, returning a 6 | json object. The json object is extended by all services. So, the result of A has 4 entries. 7 | 8 | ## Compilation 9 | 10 | Launch `mvn clean install` 11 | 12 | ## Running locally 13 | 14 | ### Launch A 15 | 16 | TODO - Add local cluster.xml 17 | 18 | ```` 19 | cd A 20 | java \ 21 | -Djava.net.preferIPv4Stack=true \ 22 | -jar target/pipeline-http-A-1.0-SNAPSHOT-fat.jar \ 23 | -conf src/main/config/config.json \ 24 | -cluster \ 25 | -cp ../etc 26 | ```` 27 | 28 | Then open a browser: 29 | 30 | ```` 31 | open http://localhost:8080/assets/index.html 32 | ```` 33 | 34 | ### Launch B 35 | 36 | ```` 37 | cd B 38 | java -Djava.net.preferIPv4Stack=true \ 39 | -jar target/pipeline-http-B-1.0-SNAPSHOT-fat.jar \ 40 | -conf src/main/config/config.json \ 41 | -cluster \ 42 | -cp ../etc 43 | ```` 44 | 45 | ### Launch C 46 | 47 | ```` 48 | cd C 49 | java -Djava.net.preferIPv4Stack=true \ 50 | -jar target/pipeline-http-C-1.0-SNAPSHOT-fat.jar \ 51 | -conf src/main/config/config.json \ 52 | -cluster \ 53 | -cp ../etc 54 | ```` 55 | 56 | ### Launch D 57 | 58 | ```` 59 | cd D 60 | java -Djava.net.preferIPv4Stack=true \ 61 | -jar target/pipeline-http-D-1.0-SNAPSHOT-fat.jar \ 62 | -conf src/main/config/config.json \ 63 | -cluster \ 64 | -cp ../etc 65 | ```` -------------------------------------------------------------------------------- /pipeline-http/README_KOR.MD: -------------------------------------------------------------------------------- 1 | # Microservice - Pipeline - HTTP 2 | 3 | 이번 데모는 파이프라인 패턴에 대해서 설명할 예정입니다.(파이프라인 패턴이란 하나의 서비스가 또다른 서비스를 부르고, 그 서비스가 또 다른 서비스를 부르는 것을 말합니다.) 4 | 5 | 이 데모는 다음과 같은 구조로 4개의 서비스를 구성하고 있습니다: A -> B-> C-> D. 모든 서비스는 json 객체를 반환하는 간단한 REST API로 구성되어 있습니다. 6 | 서비스 A의 결과는 모든 서비스(A,B,C,D)로부터 json 객체를 가져오기 때문에 4개의 json 객체를 가지고 있을 것 입니다. 7 | 8 | ## 컴파일 방법 9 | 10 | `mvn clean install`를 입력하세요. 11 | 12 | ## 로컬에서 구동하는 법 13 | 14 | ### 서비스 A 구동 15 | 16 | 우선 로컬에 cluster.xml 추가하세요 17 | 18 | ```` 19 | cd A 20 | java \ 21 | -Djava.net.preferIPv4Stack=true \ 22 | -jar target/pipeline-http-A-1.0-SNAPSHOT-fat.jar \ 23 | -conf src/main/config/config.json \ 24 | -cluster \ 25 | -cp ../etc 26 | ```` 27 | 28 | 그리고 나서 브라우저를 실행시키세요: 29 | 30 | ```` 31 | open http://localhost:8080/assets/index.html 32 | ```` 33 | 34 | ### 서비스 B 구동 35 | 36 | ```` 37 | cd B 38 | java -Djava.net.preferIPv4Stack=true \ 39 | -jar target/pipeline-http-B-1.0-SNAPSHOT-fat.jar \ 40 | -conf src/main/config/config.json \ 41 | -cluster \ 42 | -cp ../etc 43 | ```` 44 | 45 | ### 서비스 C 구동 46 | 47 | ```` 48 | cd C 49 | java -Djava.net.preferIPv4Stack=true \ 50 | -jar target/pipeline-http-C-1.0-SNAPSHOT-fat.jar \ 51 | -conf src/main/config/config.json \ 52 | -cluster \ 53 | -cp ../etc 54 | ```` 55 | 56 | ### 서비스 D 구동 57 | 58 | ```` 59 | cd D 60 | java -Djava.net.preferIPv4Stack=true \ 61 | -jar target/pipeline-http-D-1.0-SNAPSHOT-fat.jar \ 62 | -conf src/main/config/config.json \ 63 | -cluster \ 64 | -cp ../etc 65 | ```` 66 | -------------------------------------------------------------------------------- /pipeline-http/etc/cluster.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | false 7 | false 8 | false 9 | 0 10 | jdk 11 | 12 | 13 | 14 | 5701 15 | 16 | 0 17 | 18 | 19 | 20 | 224.2.2.3 21 | 54327 22 | 23 | 24 | 192.168.1.* 25 | 26 | 27 | 28 | 127.0.0.1 29 | 30 | 31 | 32 | 33 | 41 | PBEWithMD5AndDES 42 | 43 | thesalt 44 | 45 | thepass 46 | 47 | 19 48 | 49 | 50 | 51 | 52 | 16 53 | 54 | 0 55 | 56 | 57 | 58 | 63 | 1 64 | 70 | 0 71 | 77 | 0 78 | 85 | NONE 86 | 92 | 0 93 | 99 | 25 100 | 115 | com.hazelcast.map.merge.LatestUpdateMapMergePolicy 116 | 117 | 118 | 119 | 120 | 121 | 1 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /pipeline-http/etc/vertx-eventbus-service.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion" : "v1", 3 | "kind": "Service", 4 | "metadata" : { 5 | "name" : "vertx-eventbus" 6 | }, 7 | "spec" : { 8 | "clusterIP": "None", 9 | "type" : "ClusterIP", 10 | "selector" : { 11 | "vertx-cluster": "true" 12 | }, 13 | "ports": [{ 14 | "port": 5701, 15 | "protocol" : "TCP" 16 | }] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /pipeline-http/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.vertx.microservices 9 | samples 10 | 1.0-SNAPSHOT 11 | 12 | 13 | pipeline-http 14 | 15 | pom 16 | 17 | 18 | 19 | io.vertx 20 | vertx-service-discovery-bridge-kubernetes 21 | ${vertx.version} 22 | 23 | 24 | 25 | 26 | A 27 | B 28 | C 29 | D 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | io.vertx.microservices 8 | samples 9 | 1.0-SNAPSHOT 10 | 11 | pom 12 | 13 | 14 | 3.3.2 15 | 16 | 17 | 18 | pipeline-http 19 | aggregation-http 20 | 21 | 22 | 23 | 24 | 25 | io.vertx 26 | vertx-dependencies 27 | ${vertx.version} 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | 36 | io.vertx 37 | vertx-core 38 | 39 | 40 | io.vertx 41 | vertx-web 42 | 43 | 44 | io.vertx 45 | vertx-circuit-breaker 46 | ${vertx.version} 47 | 48 | 49 | io.vertx 50 | vertx-service-discovery 51 | ${vertx.version} 52 | 53 | 54 | io.vertx 55 | vertx-hazelcast 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | maven-compiler-plugin 64 | 3.5 65 | 66 | 1.8 67 | 1.8 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | openshift 76 | 77 | vertx-microservices-example 78 | ${docker.group.name}/${project.artifactId}:${project.version} 79 | fabric8/ 80 | 81 | 82 | 83 | 84 | io.fabric8 85 | docker-maven-plugin 86 | 0.14.2 87 | 88 | 89 | 90 | ${docker.image} 91 | 92 | java:8 93 | 94 | latest 95 | ${project.version} 96 | 97 | 98 | 8080 99 | 5701 100 | 101 | /opt 102 | 103 | 104 | java 105 | -jar 106 | ${project.artifactId}-${project.version}-fat.jar 107 | 108 | -conf 109 | config.json 110 | 111 | 112 | 113 | 114 | 115 | 116 | chmod -R 777 /opt 117 | chmod -R 777 /opt/* 118 | 119 | 120 | / 121 | 122 | 123 | 124 | ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar 125 | /opt 126 | 0755 127 | 128 | 129 | 130 | 131 | ${project.basedir}/src/openshift/ 132 | /opt 133 | 0755 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | http.port:8080 142 | eventbus.port:5701 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | io.fabric8 151 | fabric8-maven-plugin 152 | 2.2.96 153 | 154 | 155 | 156 | 157 | 158 | 159 | --------------------------------------------------------------------------------