Orangotango is a hotel reservation system that utilizes a modern and scalable microservices architecture.
- Projects
- Architecture
- Application Overview
- How to Run with Docker
- Observability
- Logs and Tracing
- How to Contribute
- Next Steps
- License
Orangotango is composed of six main projects, each playing a specific role in the system's architecture:
- orangotango-app: A Single Page Application (SPA) built with Angular that communicates with the orangotango-api-gateway.
- orangotango-api-gateway: API Gateway using Ocelot to centralize requests for rooms and reservations microservices into a single entry point.
- orangotango-rooms: A microservice responsible for providing information about the available rooms at the hotel.
- orangotango-reservations: A microservice responsible for managing the reservation process at the hotel.
- orangotango-notifications: A microservice responsible for sending notifications.
- orangotango-packages: Shared packages among the microservices, providing common functionalities, which are:
-
Orangotango.Core
: The kernel package for microservices, encompassing abstractions for messaging, events, repositories, services, aggregations, and more. -
Orangotango.Api
: This package provides APIs centralizing Swagger configuration, standardized response patterns, middleware for logging incoming requests and outgoing responses. -
Orangotango.Events
: Contains all solution events, establishing contracts for easy integration via messaging topology, facilitating data replication across microservices. -
Orangotango.Infra
: Includes infrastructure-related configurations such as Entity Framework contexts, ELK-based logging configuration, Messaging using Mass Transit and RabbitMQ, among others.
-
Below is a diagram of the application architecture, illustrating how the microservices communicate with each other:
Orangotango's microservices, implemented in .NET, are designed using a Hexagonal / Event-Driven Architecture (EDA).
The system emphasizes responsibility separation, adhering to SOLID, Clean Code, and Domain-Driven Design (DDD) principles. The microservices are organized into distinct layers:
- Presentation Layer: Includes a Web API with controllers and input models (DTOs) defining endpoint contracts.
- Application Layer: Consists of Command Handlers, Mappers, Results, and Services.
- Domain Layer: Comprises Entities, Commands, Validations, and Repository Abstractions.
- Infrastructure Layer: Implements Repositories, the EF Context, and a Messaging Bus.
In the Orangotango project, CQRS is implemented by separating write commands and read queries:
-
Write Commands (Upsert Command): Insert or update operations start in the presentation layer (Web API), move through the application layer to apply business logic in the domain layer, and are then persisted in the database by the infrastructure layer.
-
Read Queries (Query Command): Read operations begin in the presentation layer and interact directly with the infrastructure. The flow is bidirectional, allowing data to be returned to the presentation layer for display to the user.
See below an example of implementation using the aforementioned layers in orangotango-rooms:
- Hexagonal / Event-Driven Architecture (EDA).
- CQRS (Command Query Responsibility Segregation), DDD, SOLID, and Clean Code principles.
- Service Layer, Repository Pattern, Notification Pattern, and Unit Of Work.
- Resilience best practices including Retry Pattern, Circuit Breaker, and Exponential Backoff.
Feel free to contribute to this project. For more information, refer to the individual repositories of each project.
The frontend was developed using Angular and is based on the Modernize template (available at: Modernize Angular Material Dashboard).
Below, you can find screenshots of the main screens in the system.
To run the project using Docker, you can use the docker-compose.yml
file, which sets up all the necessary services for Orangotango. Follow the steps below:
-
Make sure you have Docker and Docker Compose installed.
-
Clone the Orangotango repository.
git clone https://github.com/wesleycosta/orangotango.git
-
Run Docker Compose.
In the root directory of the project, run the command below to start all the services defined in the
docker-compose.yml
file:docker-compose up
This will start the following services:
- Elasticsearch
- Kibana
- SQL Server
- RabbitMQ
- orangotango-rooms
- orangotango-reservations
- orangotango-api-gateway
- orangotango-app
-
Access the services.
- Web Application (SPA): http://localhost:81
- API Gateway: http://localhost:8080
- Rooms Service: http://localhost:8081/api-docs
- Reservations Service: http://localhost:8082/api-docs
- Elasticsearch: http://localhost:9200
- Kibana: http://localhost:5601
- RabbitMQ Management: http://localhost:15672
-
Shut down the services.
To stop all the services, press
Ctrl+C
in the terminal where the services are running, and then run:docker-compose down
To monitor communication between microservices, a TraceId
field has been added to logs. This field enables tracking all stages of a specific operation, facilitating comprehensive tracing of its journey.
In the following example, a new room named Master 01
is created in the rooms microservice. Using the TraceId
, we can trace every step of this process, from the initial request to the final processing in the reservations microservice.
Below is the sequence of logs captured in Kibana for this operation:
- ReceivedRequest (orangotango-rooms, 15:55:13.090): The rooms microservice receives the request to create a new room.
- EventPublished (orangotango-rooms, 15:55:13.249): After creating the room, the
RoomUpsertedEvent
is published by the rooms microservice. - ReturnedResponse (orangotango-rooms, 15:55:13.251): The rooms microservice returns the response to the POST request.
- EventReceived (orangotango-reservations, 15:55:13.336): The reservations microservice receives the
RoomUpsertedEvent
. - EventProcessedSuccessfully (orangotango-reservations, 15:55:13.379): The reservations microservice successfully processes the
RoomUpsertedEvent
.
The TraceId
field in each log entry allows correlating these events, making it easier to visualize the complete flow of an operation across different microservices.
This detailed logging and tracing mechanism is crucial for debugging and monitoring the system, ensuring all operations can be audited and analyzed in case of failures or for future optimizations.
- Fork the project
- Create a branch for your feature (
git checkout -b feature/new-feature
) - Commit your changes (
git commit -m 'Add new feature'
) - Push to the branch (
git push origin feature/new-feature
) - Open a Pull Request
- Complete Microservices Development and Unit Tests: Finalize the development of current microservices and create unit tests.
- Kubernetes Deployment: Deploy microservices on Kubernetes for high availability, scalability, and ease of management.
- CI/CD Enhancement: Expand CI/CD pipelines with GitHub Actions to include additional deployment steps and code quality monitoring.
- Improve Application Resilience: Implement Circuit Breaker and Retry Pattern to enhance robustness and handle temporary failures effectively.
This project is licensed under the MIT License. See the LICENSE file for details.