This project demonstrates a microservice architecture using the following components:
- naming-server: Acts as the Eureka server for service discovery.
- currency-exchange: A microservice that provides currency exchange rates.
- currency-conversion: A microservice that calculates currency conversions by calling the currency-exchangeservice.
- api-gateway: A gateway that routes requests to the appropriate microservices and provides load balancing.
- Service Discovery: Microservices (currency-exchangeandcurrency-conversion) register themselves with thenaming-server. Theapi-gatewaydynamically discovers these services.
- Load Balancing: The api-gatewayuses Eureka to distribute requests across multiple instances of a service.
- Fault Tolerance: Resilience4j is integrated into the microservices to handle failures gracefully.
- Service Registration:
- currency-exchangeand- currency-conversionregister with the- naming-server.
- The api-gatewayqueries thenaming-serverto discover available services.
 
- Request Flow:
- A client sends a request to the api-gateway.
- The api-gatewayroutes the request to the appropriate service (e.g.,currency-conversion).
- If currency-conversionneeds exchange rates, it calls thecurrency-exchangeservice.
 
- A client sends a request to the 
- Load Balancing:
- If multiple instances of currency-exchangeorcurrency-conversionare running, theapi-gatewaydistributes requests among them.
 
- If multiple instances of 
- A client requests a currency conversion via the api-gateway:curl http://localhost:8000/currency-conversion/from/USD/to/INR/quantity/100 
- The api-gatewayroutes the request to thecurrency-conversionservice.
- The currency-conversionservice calls thecurrency-exchangeservice to get the exchange rate.
- The response is returned to the client via the api-gateway.
- Circuit Breaker: Prevents repeated calls to a failing service by "breaking" the circuit after a threshold of failures.
- Retry: Automatically retries failed operations based on a configurable retry policy.
- Rate Limiter: Limits the number of requests to a service within a specified time window.
- Bulkhead: Limits the number of concurrent calls to a service to prevent resource exhaustion.
- Time Limiter: Ensures operations complete within a specified timeout duration.
Add the following dependency to your pom.xml:
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot3</artifactId>
    <version>2.0.2</version>
</dependency>The following configuration is used to define the behavior of Resilience4j features:
resilience4j.circuitbreaker.instances.myService.failure-rate-threshold=50
# If 50% of the requests fail, the circuit breaker will open.
resilience4j.circuitbreaker.instances.myService.sliding-window-size=10
# The circuit breaker will evaluate the last 10 requests to calculate the failure rate.
resilience4j.circuitbreaker.instances.myService.wait-duration-in-open-state=10000
# The circuit breaker will remain open for 10 seconds before transitioning to a half-open state.resilience4j.retry.instances.myService.max-attempts=3
# The service will retry a failed operation up to 3 times.
resilience4j.retry.instances.myService.wait-duration=500ms
# The service will wait 500 milliseconds between retry attempts.resilience4j.ratelimiter.instances.myService.limit-for-period=5
# Allows up to 5 requests per second.
resilience4j.ratelimiter.instances.myService.limit-refresh-period=1s
# The rate limiter refreshes its limit every 1 second.resilience4j.bulkhead.instances.myService.max-concurrent-calls=3
# Allows up to 3 concurrent calls to the service.
resilience4j.bulkhead.instances.myService.max-wait-duration=0
# If the bulkhead is full, additional calls will immediately fail without waiting.resilience4j.timelimiter.instances.myService.timeout-duration=2s
# If a service call takes longer than 2 seconds, it will time out and trigger the fallback.- Behavior: Simulates a failure and triggers the circuit breaker.
- Fallback Response: Fallback response: Simulated failure.
- Example Command:
curl http://localhost:8000/circuit-breaker 
- Expected Result:
- Initially, the service will fail.
- After repeated failures, the circuit will open, and the fallback response will be returned.
 
- Behavior: Simulates a failure and retries the operation up to 3 times before triggering the fallback.
- Fallback Response: Fallback response: Simulated failure.
- Example Command:
curl http://localhost:8000/retry 
- Expected Result:
- The service will retry up to 3 times.
- If all attempts fail, the fallback response will be returned.
 
- Behavior: Limits the number of requests to 5 per second. Excess requests trigger the fallback.
- Fallback Response: Fallback response: Request not permitted.
- Example Command:
curl http://localhost:8000/rate-limiter 
- Expected Result:
- Up to 5 requests per second will succeed.
- Additional requests within the same second will trigger the fallback response.
 
- Behavior: Limits the number of concurrent calls to 3. Excess calls trigger the fallback.
- Fallback Response: Fallback response: Bulkhead full.
- Example Command:
curl http://localhost:8000/bulkhead 
- Expected Result:
- Up to 3 concurrent calls will succeed.
- Additional concurrent calls will trigger the fallback response.
 
- Behavior: Simulates a delay. If the operation takes longer than 2 seconds, the fallback is triggered.
- Fallback Response: Fallback response: Timeout.
- Example Command:
curl http://localhost:8000/time-limiter 
- Expected Result:
- If the operation completes within 2 seconds, the normal response will be returned.
- If the operation exceeds 2 seconds, the fallback response will be returned.
 
To repeatedly call the endpoints and observe the behavior, use the watch command:
watch -n 1 curl http://localhost:8000/{endpoint}Replace {endpoint} with the specific endpoint you want to test:
- /circuit-breaker
- /retry
- /rate-limiter
- /bulkhead
- /time-limiter
For example:
watch -n 1 curl http://localhost:8000/circuit-breakerTo create a Docker image for the Spring application, follow these steps:
- Ensure Docker is installed and running on your machine.
- Build the Docker image using Maven:
This command will generate a Docker image for the application using the Spring Boot plugin.mvn spring-boot:build-image -DskipTests 
To run the application and its dependencies using Docker Compose:
- Ensure docker-compose.ymlis properly configured in the project directory.
- Start the services using Docker Compose:
docker-compose up 
- To run the services in detached mode, use:
docker-compose up -d 
Once the services are running, you can verify the application:
- Access the application at http://localhost:<port>(replace<port>with the configured port indocker-compose.yml).
- Check the logs using:
docker-compose logs 
To stop the running services, use:
docker-compose downThe application.properties file is used to configure the mapping between services. Below is an example of how services are mapped:
# Service URLs
currency-exchange-service.url=http://currency-exchange:8000
currency-conversion-service.url=http://currency-conversion:8100
api-gateway-service.url=http://api-gateway:8765- currency-exchange-service.url: Maps to the currency-exchangeservice running on port8000.
- currency-conversion-service.url: Maps to the currency-conversionservice running on port8100.
- api-gateway-service.url: Maps to the api-gatewayservice running on port8765.
These mappings allow the services to communicate with each other using their respective URLs. Ensure that the service names match the ones defined in docker-compose.yml.