Skip to content

Latest commit

 

History

History

rest-fights

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Superheroes Fight Microservice

Table of Contents

Introduction

This is the Fight REST API microservice. It is a reactive HTTP microservice exposing an API for performing fights between Heroes and Villains. Each fight is persisted into a MongoDB database and can be retrieved via the REST API. This service is implemented using RESTEasy Reactive with reactive endpoints and Quarkus MongoDB Reactive with Panache's active record pattern.

Fight messages are also published on an Apache Kafka topic called fights. The event-statistics service listens for these events. Messages are stored in Apache Avro format and the fight schema is automatically registered in the Apicurio Schema Registry. This all uses built-in extensions from Quarkus.

rest-fights

Exposed Endpoints

The following table lists the available REST endpoints. The OpenAPI document for the REST endpoints is also available.

Path HTTP method Response Status Response Object Description
/api/fights GET 200 List<Fight> All Fights. Empty array ([]) if none.
/api/fights POST 200 Fight Performs a fight.
/api/fights POST 400 Invalid Fighters passed in request body (or no request body found)
/api/fights/randomfighters GET 200 Fighters Finds random fighters
/api/fights/{id} GET 200 Fight Fight with id == {id}
/api/fights/{id} GET 404 No Fight with id == {id} found
/api/fights/hello/heroes GET 200 String Invokes the "hello" endpoint of the Heroes microservice
/api/fights/hello/villains GET 200 String Invokes the "hello" endpoint of the Villains microservice

Configuration

The FightConfig stores all the application-specific configuration that can be overridden at runtime.

Resiliency

Timeouts

The FightService class uses timeouts from SmallRye Fault Tolerance to protect against calls to the downstream Hero and Villain services. Tests for these conditions can be found in FightServiceTests.

Fallbacks

The FightService class uses fallbacks from SmallRye Fault Tolerance to protect against calls to the downstream Hero and Villain services. Tests for these conditions can be found in FightServiceTests.

Retries

Retry logic to the downstream Hero and Villain services is implemented in the clients for each service.

Hero Client

The HeroRestClient is implemented using the reactive rest client. All of its configuration can be found in application.properties under the quarkus.rest-client.hero-client key. This client is not exposed outside of the io.quarkus.sample.superheroes.fight.client package.

Instead, the HeroClient class wraps the HeroRestClient and adds some resiliency to it:

  • The downstream Hero service returns a 404 if no random Hero is found. HeroClient handles this case and simulates the service returning nothing.
  • In the event the downstream Hero service returns an error, HeroClient adds 3 retries with a 200ms delay between each retry.

Villain Client

The VillainClient is implemented using the JAX-RS client API with the RESTEasy Reactive client. All of its configuration can be found in application.properties under the fight.villain.client-base-url key.

  • The downstream Villain service returns a 404 if no random Villain is found. VillainClient handles this case and simulates the service returning nothing.
  • In the event the downstream Villain service returns an error, VillainClient adds 3 retries with a 200ms delay between each retry.

Service Discovery and Client Load Balancing

The fight service implements service discovery and client-side load balancing when making downstream calls to the rest-heroes and rest-villains services. The service discovery is implemented in Quarkus using SmallRye Stork.

Stork integrates directly with the Quarkus REST Client Reactive. This means that there is no additional code needed in order to take advantage of Stork's service discovery and client-side load balancing.

You could disable Stork completely for the HeroRestClient by setting quarkus.rest-client.hero-client.url to any non-Stork URL (i.e. something that doesn't start with stork://). Similarly, you could disable Stork completely for the VillainClient by setting fight.villain.client-base-url to any non-Stork URL.

Service Discovery

In local development mode, as well as when running via Docker Compose, SmallRye Stork is configured using static list discovery. In this mode, the downstream URLs are statically defined in an address list. In application.properties, see the quarkus.stork.hero-service.service-discovery.address-list and quarkus.stork.villain-service.service-discovery.address-list properties.

When running in Kubernetes, Stork is configured to use the Kubernetes Service Discovery. In this mode, Stork will read the Kubernetes Services for the rest-heroes and rest-villains services to obtain the instance information. Additionally, the instance information has been configured to refresh every minute. See the rest-fights-config ConfigMap in the Kubernetes deployment descriptors. Look for the quarkus.stork.* properties within the various ConfigMaps.

All of the other Stork service discovery mechanisms (Consul and Eureka) can be used simply by updating the configuration appropriately according to the Stork documentation.

Client-Side Load Balancing

In all cases, the default load balancing algorithm used is round robin. All of the other load balancing algorithms (random, least requests, least response time, and power of two choices) are available on the application's classpath, so feel free to play around with them by updating the configuration appropriately according to the Stork documentation.

Testing

This application has a full suite of tests, including an integration test suite.

Contract testing with Pact

Pact is a code-first tool for testing HTTP and message integrations using contract tests. Contract tests assert that inter-application messages conform to a shared understanding that is documented in a contract. Without contract testing, the only way to ensure that applications will work correctly together is by using expensive and brittle integration tests.

Eric Deandrea and Holly Cummins recently spoke about contract testing with Pact and used the Quarkus Superheroes for their demos. Watch the replay and view the slides if you'd like to learn more about contract testing.

The rest-fights application is both a Pact Consumer and a Pact Provider. As a Consumer, it should be responsible for defining the contracts between itself and its providers (rest-heroes & rest-villains). As a Provider, is should run provider verification tests against contracts produced by consumers.

As this README states, contracts generally should be hosted in a Pact Broker and then automatically discovered in the provider verification tests.

One of the main goals of the Superheroes application is to be super simple and just "work" by anyone who may clone this repo. That being said, we can't make any assumptions about where a Pact broker may be or any of the credentials required to access it.

The FightServiceConsumerContractTests.java test class generates the rest-fights-rest-heroes.json and rest-fights-rest-villains.json contracts while also providing mock instances of the rest-heroes and rest-villains providers.

The contracts are committed into the provider's version control simply for easy of use and reproducibility.

Additionally, the Pact contract is committed into this application's source tree inside the src/test/resources/pacts directory.

The consumer contract tests and provider verification tests ARE executed during this project's CI/CD processes. They run against any pull requests and any commits back to the main branch.

The Pact tests use the Quarkus Pact extension. This extension is recommended to give the best user experience and ensure compatibility.

Running the Application

First you need to start up all of the downstream services (Heroes Service and Villains Service - the Event Statistics Service is optional).

The application runs on port 8082 (defined by quarkus.http.port in application.properties).

From the quarkus-super-heroes/rest-fights directory, simply run ./mvnw quarkus:dev to run Quarkus Dev Mode, or running quarkus dev using the Quarkus CLI. The application will be exposed at http://localhost:8082 and the Quarkus Dev UI will be exposed at http://localhost:8082/q/dev. Quarkus Dev Services will ensure the MongoDB instance, an Apache Kafka instance, and an Apicurio Schema Registry are all started and configured.

NOTE: Running the application outside of Quarkus Dev Mode requires standing up a MongoDB instance, an Apache Kafka instance, and an Apicurio Schema Registry and binding them to the app.

Furthermore, since this service also communicates with additional downstream services (rest-heroes and rest-villains), those would need to be stood up as well, although this service does have fallbacks in case those other services aren't available.

By default, the application is configured with the following:

Description Environment Variable Java Property Value
Database Host QUARKUS_MONGODB_HOSTS quarkus.mongodb.hosts localhost:27017
Database username QUARKUS_MONGODB_CREDENTIALS_USERNAME quarkus.mongodb.credentials.username superfight
Database password QUARKUS_MONGODB_CREDENTIALS_PASSWORD quarkus.mongodb.credentials.password superfight
Kafka Bootstrap servers KAFKA_BOOTSTRAP_SERVERS kafka.bootstrap.servers PLAINTEXT://localhost:9092
Apicurio Schema Registry MP_MESSAGING_CONNECTOR_SMALLRYE_KAFKA_APICURIO_REGISTRY_URL mp.messaging.connector.smallrye-kafka.apicurio.registry.url http://localhost:8086/apis/registry/v2
Heroes Service URL QUARKUS_REST_CLIENT_HERO_CLIENT_URL quarkus.rest-client.hero-client.url stork://hero-service
Villains Service URL FIGHT_VILLAIN_CLIENT_BASE_URL fight.villain.client-base-url stork://villain-service

Running Locally via Docker Compose

Pre-built images for this application can be found at quay.io/quarkus-super-heroes/rest-fights.

Only Fights Service

Pick one of the 4 versions of the application from the table below and execute the appropriate docker compose command from the quarkus-super-heroes/rest-fights directory.

NOTE: You may see errors as the applications start up. This may happen if an application completes startup before one if its required services (i.e. database, kafka, etc). This is fine. Once everything completes startup things will work fine.

Description Image Tag Docker Compose Run Command
JVM Java 17 java17-latest-rhbq-3.2 docker compose -f deploy/docker-compose/java17.yml up --remove-orphans
Native native-latest-rhbq-3.2 docker compose -f deploy/docker-compose/native.yml up --remove-orphans

Fights Service and all Downstream Dependencies

The above Docker Compose files are meant for standing up this application and the required database, Kafka broker, and Apicurio Schema Registry only. If you want to stand up this application and its downstream services (rest-villains and rest-heroes), pick one of the 4 versions from the table below and execute the appropriate docker compose command from the quarkus-super-heroes/rest-fights directory.

NOTE: You may see errors as the applications start up. This may happen if an application completes startup before one if its required services (i.e. database, kafka, etc). This is fine. Once everything completes startup things will work fine.

Description Image Tag Docker Compose Run Command
JVM Java 17 java17-latest-rhbq-3.2 docker compose -f deploy/docker-compose/java17-all-downstream.yml up --remove-orphans
Native native-latest-rhbq-3.2 docker compose -f deploy/docker-compose/native-all-downstream.yml up --remove-orphans

Only Downstream Dependencies

If you want to develop the Fights service (i.e. via Quarkus Dev Mode) but want to stand up just it's downstream services (rest-villains and rest-heroes), pick one of the 4 versions from the table below and execute the appropriate docker compose command from the quarkus-super-heroes directory.

NOTE: You may see errors as the applications start up. This may happen if an application completes startup before one if its required services (i.e. database, kafka, etc). This is fine. Once everything completes startup things will work fine.

Description Image Tag Docker Compose Run Command
JVM Java 17 java17-latest-rhbq-3.2 docker compose -f rest-heroes/deploy/docker-compose/java17.yml -f rest-villains/deploy/docker-compose/java17.yml up --remove-orphans
Native native-latest-rhbq-3.2 docker compose -f rest-heroes/deploy/docker-compose/native.yml -f rest-villains/deploy/docker-compose/native.yml up --remove-orphans

If you want to stand up the entire system, follow these instructions.

Once started the application will be exposed at http://localhost:8082. The Apicurio Schema Registry will be exposed at http://localhost:8086.

Deploying to Kubernetes

The application can be deployed to Kubernetes using pre-built images or by deploying directly via the Quarkus Kubernetes Extension. Each of these is discussed below.

Using pre-built images

Pre-built images for this application can be found at quay.io/quarkus-super-heroes/rest-fights.

Deployment descriptors for these images are provided in the deploy/k8s directory. There are versions for OpenShift, Minikube, Kubernetes, and KNative.

Pick one of the 4 versions of the application from the table below and deploy the appropriate descriptor from the deploy/k8s directory.

Description Image Tag OpenShift Descriptor Minikube Descriptor Kubernetes Descriptor KNative Descriptor
JVM Java 17 java17-latest-rhbq-3.2 java17-openshift.yml java17-minikube.yml java17-kubernetes.yml java17-knative.yml
Native native-latest-rhbq-3.2 native-openshift.yml native-minikube.yml native-kubernetes.yml native-knative.yml

The application is exposed outside of the cluster on port 80.

These are only the descriptors for this application and the required database, Kafka broker, and Apicurio Schema Registry only. If you want to deploy this application and its downstream services (rest-villains and rest-heroes), pick one of the 4 versions of the application from the table below and deploy the appropriate descriptor from the rest-fights/deploy/k8s directory.

Description Image Tag OpenShift Descriptor Minikube Descriptor Kubernetes Descriptor KNative Descriptor
JVM Java 17 java17-latest-rhbq-3.2 java17-openshift-all-downstream.yml java17-minikube-all-downstream.yml java17-kubernetes-all-downstream.yml java17-knative-all-downstream.yml
Native native-latest-rhbq-3.2 native-openshift-all-downstream.yml native-minikube-all-downstream.yml native-kubernetes-all-downstream.yml native-knative-all-downstream.yml

Each application is exposed outside of the cluster on port 80.

If you want to deploy the entire system, follow these instructions.

Deploying directly via Kubernetes Extensions

Following the deployment section of the Quarkus Kubernetes Extension Guide (or the deployment section of the Quarkus OpenShift Extension Guide if deploying to OpenShift), you can run one of the following commands to deploy the application and any of its dependencies (see Kubernetes (and variants) resource generation of the automation strategy document) to your preferred Kubernetes distribution.

NOTE: For non-OpenShift or minikube Kubernetes variants, you will most likely need to push the image to a container registry by adding the -Dquarkus.container-image.push=true flag, as well as setting the quarkus.container-image.registry, quarkus.container-image.group, and/or the quarkus.container-image.name properties to different values.

Target Platform Java Version Command
Kubernetes 17 ./mvnw clean package -Dquarkus.profile=kubernetes -Dquarkus.kubernetes.deploy=true -DskipTests
OpenShift 17 ./mvnw clean package -Dquarkus.profile=openshift -Dquarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000 -Dquarkus.container-image.group=$(oc project -q) -Dquarkus.kubernetes.deploy=true -DskipTests
Minikube 17 ./mvnw clean package -Dquarkus.profile=minikube -Dquarkus.kubernetes.deploy=true -DskipTests
KNative 17 ./mvnw clean package -Dquarkus.profile=knative -Dquarkus.kubernetes.deploy=true -DskipTests
KNative (on OpenShift) 17 ./mvnw clean package -Dquarkus.profile=knative-openshift -Dquarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000 -Dquarkus.container-image.group=$(oc project -q) -Dquarkus.kubernetes.deploy=true -DskipTests

You may need to adjust other configuration options as well (see Quarkus Kubernetes Extension configuration options and Quarkus OpenShift Extension configuration options).

The do_build function in the generate-k8s-resources.sh script uses these extensions to generate the manifests in the deploy/k8s directory.