|
| 1 | +<div class="anchored-md"> |
| 2 | +{{#assign "markdown"}} |
| 3 | +Microservices has become an industry standard term and everyone is jumping aboard the hype train. There are definitely pros and cons in both building and maintaining microservices, however, they will not be discussed in this article, just remember [you are not Google](https://blog.bradfieldcs.com/you-are-not-google-84912cf44afb). We are going to show some options for sharing endpoints across services as well as run multiple services in a single JVM. |
| 4 | + |
| 5 | +## Services |
| 6 | +Since we are talking about code reuse, let's grab our `RouteHandler`'s from two previous examples to demonstrate. We will be using our [lightweight REST server example](/posts/lightweight-embedded-java-rest-server-without-a-framework#routing-server) as well as the simple [content types example](/posts/handling-content-types-with-undertow#content-type-routes). To start we are going to run each of them as their own stand alone service on their own port. |
| 7 | + |
| 8 | +{{> templates/src/widgets/code/code-snippet file=services section=services.sections.restServer}} |
| 9 | +<pre class="line-numbers"><code class="language-text">curl -X POST "localhost:8080/users" -d ' |
| 10 | +{ |
| 11 | + "email": "user1@test.com", |
| 12 | + "roles": ["USER"] |
| 13 | +} |
| 14 | +'; |
| 15 | +{ |
| 16 | + "email" : "user1@test.com", |
| 17 | + "roles" : [ "USER" ], |
| 18 | + "dateCreated" : "2017-09-04" |
| 19 | +} |
| 20 | + |
| 21 | +curl -X GET "localhost:8080/users/user1@test.com" |
| 22 | +{ |
| 23 | + "email" : "user1@test.com", |
| 24 | + "roles" : [ "USER" ], |
| 25 | + "dateCreated" : "2017-09-04" |
| 26 | +}</code></pre> |
| 27 | + |
| 28 | +{{> templates/src/widgets/code/code-snippet file=services section=services.sections.contentTypesServer}} |
| 29 | +<pre class="line-numbers"><code class="language-text">curl localhost:8081/helloWorldText |
| 30 | +Hello World</code></pre> |
| 31 | +Everything looks good we are in business. |
| 32 | + |
| 33 | +## Combining RoutingHandlers |
| 34 | +A simple use case for shared routes would be ping / healthchecks / server status that all of your services might share. We don't have one prepared so use your imagination with our existing services. With `RoutingHandler.addAll` we can combine both `RoutingHandler`'s into a single `RoutingHandler` and have a server listen to all of the routes on a single port. This allows us to combine common code across routing handlers or even run multiple micro services together under a single port (see next section for some reasons why you might want to do this). |
| 35 | + |
| 36 | +{{> templates/src/widgets/code/code-snippet file=services section=services.sections.combinedServer}} |
| 37 | +<pre class="line-numbers"><code class="language-text">curl -X POST "localhost:8082/users" -d ' |
| 38 | +{ |
| 39 | + "email": "user1@test.com", |
| 40 | + "roles": ["USER"] |
| 41 | +} |
| 42 | +'; |
| 43 | +{ |
| 44 | + "email" : "user1@test.com", |
| 45 | + "roles" : [ "USER" ], |
| 46 | + "dateCreated" : "2017-09-04" |
| 47 | +} |
| 48 | + |
| 49 | +curl -X GET "localhost:8082/users/user1@test.com" |
| 50 | +{ |
| 51 | + "email" : "user1@test.com", |
| 52 | + "roles" : [ "USER" ], |
| 53 | + "dateCreated" : "2017-09-04" |
| 54 | +}</code></pre> |
| 55 | +<pre class="line-numbers"><code class="language-text">curl localhost:8082/helloWorldText |
| 56 | +Hello World</code></pre> |
| 57 | +Once again everything is working but under a single port this time. |
| 58 | + |
| 59 | +## One Server Listening on Multiple Ports |
| 60 | +Testing microservices, especially ones that depend on other services to be up can be quite the pain. You either need to run N services in your IDE / command line or possibly set up something like docker so it is easy to reproduce. With each of these sometimes you need to remember which order to start each service in, yikes lots of fun. If all of our services are Java based and use the same dependencies we have another option. We already showed that the services could be combined into a single `RoutingHandler`. Maybe this doesn't meet your needs and each service is split by port and expects everything to work that way. Undertow has you covered, we can run multiple ports in a single undertow instance. |
| 61 | + |
| 62 | +Note: If you have proper loose coupling both of the servers shouldn't be accessible from the same maven / gradle project so what do we do? Just make a new module that includes both server modules. This is not ideal and not necessarily recommended for prod since there could be some dependency issues. However if the dependencies line up across services (not such a bad thing to enforce especially on smaller teams / code bases) we can make such a shortcut. Whether you run this way in prod to reduce OPS work or only run this mode in development to save time is up to you. If you have a low traffic app running them together might make perfect sense. You would essentially have microservice ready code which can easily be split out into its own service when needed but for now it just shares the same CI pipeline, deploy script, and servers. |
| 63 | + |
| 64 | +{{> templates/src/widgets/code/code-snippet file=services section=services.sections.multiPortServer}} |
| 65 | +<pre class="line-numbers"><code class="language-text">curl -X POST "localhost:8083/users" -d ' |
| 66 | +{ |
| 67 | + "email": "user1@test.com", |
| 68 | + "roles": ["USER"] |
| 69 | +} |
| 70 | +'; |
| 71 | +{ |
| 72 | + "email" : "user1@test.com", |
| 73 | + "roles" : [ "USER" ], |
| 74 | + "dateCreated" : "2017-09-04" |
| 75 | +} |
| 76 | + |
| 77 | +curl -X GET "localhost:8083/users/user1@test.com" |
| 78 | +{ |
| 79 | + "email" : "user1@test.com", |
| 80 | + "roles" : [ "USER" ], |
| 81 | + "dateCreated" : "2017-09-04" |
| 82 | +}</code></pre> |
| 83 | +<pre class="line-numbers"><code class="language-text">curl localhost:8084/helloWorldText |
| 84 | +Hello World</code></pre> |
| 85 | +Surprise, its all working under a single Undertow instance but listening on multiple ports. |
| 86 | + |
| 87 | + |
| 88 | +## MicroserviceService |
| 89 | +Let's take it one step too far just for fun. What if our service itself spun up new services inside the same JVM listening on new ports. Totally useless? probably, possible? Totally! |
| 90 | + |
| 91 | +{{> templates/src/widgets/code/code-snippet file=services section=services.sections.microserviceService}} |
| 92 | +<pre class="line-numbers"><code class="language-text">curl localhost:9000 |
| 93 | +curl: (7) Failed to connect to localhost port 9000: Connection refused</code></pre> |
| 94 | +<pre class="line-numbers"><code class="language-text">curl localhost:8085/?port=9000 |
| 95 | +server with port 9000 created</code></pre> |
| 96 | +<pre class="line-numbers"><code class="language-text">curl localhost:9000 |
| 97 | +web server with port 9000</code></pre> |
| 98 | + |
| 99 | +### Bonus |
| 100 | +All of the above examples are inside of a single main method and all run together in the same JVM. Click any of the github links to view the source. |
| 101 | + |
| 102 | +{{/assign}} |
| 103 | +{{md markdown}} |
| 104 | +</div> |
0 commit comments