A small system-design challenge to practice and tinker with { "docker", "GoLang", "Ruby-on-Rails", "MySQL", "RabbitMQ", "ElasticSearch" }
Our goal is to build a scalable & robust chat app that contains the following requirements:
- Business Entities:
- Application (aka. User), can have many chats.
- Chat, can have many messages.
- Message.
- Chats and Messages have a number that increments for each Application and Chat respectively.
- Client can Create/Read/Update Applications/Chats/Messages, and search messages.
- Client can search Messages.
The system is designed as a microservices architecture, with the following components:
- Main App (Ruby on Rails): Accepts HTTP requests for the the app resources. Serves the Application resource requests, and redirects other requests back to Go service.
- Chats/Messages Service (Go): Handles the Chat/Message creation/update by generating a number for the resource and publishing a RabbitMQ-message. And reading Chat/Message goes directly to MySQL.
- RabbitMQ: A message broker to act as a medium between the Rails/Go services and MySQL for asynchronous communication.
- Ruby-Whenever (Cron): A background processes to count Chats and Messages periodically and persist results in MySQL as a method of caching.
- Consumer (Ruby): Consumes Chats/Messages published RabbitMQ-messages for resources creation/update and serve send a bulk insert/update in MySQL.
- Elasticsearch: Searching Messages.
- Redis: For caching chats and messages numbers.
- RDBMS (MySQL): Stores Applications/Chats/Messages.
To run the system locally, follow these steps:
- Clone the repository:
git clone https://github.com/ShadyZekry/chat-app.git
cd <repository-directory>
- Build and Run Docker Containers:
docker-compose up --build
- Access the system (for inspection):
-
Create Application
curl --location 'localhost:3000/api/v1/applications' \ --form 'name="application-name"'
-
Get Application
curl --location 'localhost:3000/api/v1/applications/1d763d85-1b08-4941-97fe-e6937931054f'
-
Update Application
curl --location --request PUT 'localhost:3000/api/v1/applications/1d763d85-1b08-4941-97fe-e6937931054f'
-
Create Chat
curl --location 'localhost:8080/api/v1/applications/1d763d85-1b08-4941-97fe-e6937931054f/chats' \ --form 'name="name2"'
-
Get Chat
curl --location 'localhost:8080/api/v1/applications/1d763d85-1b08-4941-97fe-e6937931054f/chats/4'
-
Update Chat
curl --location --request PUT 'localhost:8080/api/v1/applications/1d763d85-1b08-4941-97fe-e6937931054f/chats/4' \ --form 'name="test"'
-
Create Message
curl --location 'localhost:8080/api/v1/applications/1d763d85-1b08-4941-97fe-e6937931054f/chats/4/messages' \ --form 'name="name2"'
-
Get Message
curl --location 'localhost:8080/api/v1/applications/1d763d85-1b08-4941-97fe-e6937931054f/chats/4/messages/3'
-
Update Message
curl --location --request PUT 'localhost:8080/api/v1/applications/1d763d85-1b08-4941-97fe-e6937931054f/chats/4/messages/3' \ --form 'name="test"'
-
Check the internals (For inspection not as APIs) - Main App:
http://localhost:8080
- Redis:http://localhost:6379
- RabbitMQ admin-panel:http://localhost:15672
- Username:
guest
- Password:
guest
- Elasticsearch:http://localhost:9200
- MySQL:localhost:3306
- Username:
root
- Password:
password
- Username:
-
- Rate Limiting: Implement rate limiting to prevent abuse and ensure fair usage.
- Adding Specs: Add unit tests to the codebase to ensure reliability and maintainability.
- Retry Mechanism: Add retry mechanisms for transient failures in asynchronous communication between microservices.
- Monitoring and Logging: Enhance monitoring and logging to gain better insights into the system's behavior and performance.
- Data Coalescing: Combine multiple Create/Update requests on the Consumer lever to reduce the hit on MySQL.
- Elastic search is not yet fully configured.
- Application goes directly to MySQL. The idea behind that decision is that Application creation should not have that huge impact on the system relative to Chats/Messages.