I had a lot of fun in completing this challenge because of the wide variety of topics that it covers ranging from architecture to system design to data analysis and modelling to considering performance and automating deployments. It was indeed a pleasure for me to have been offered this challenge as it tested my knowledge, and skills while giving me an idea on the kind of work that sharenow does.
Technology | Implementations/Frameworks | Version | Purpose |
---|---|---|---|
Java | Hotspot VM | 11 | JVM |
Java | Spring Boot | 2.3.x | REST API framework |
Java | Spring Cloud | Hoxton | Microservice framework |
Java | Java Topology Suite | 1.14 | Geometric algorithms |
Java | Open Zipkin | 2.23.3-SNAPSHOT | Distributed tracing |
Java | JUnit | 5 | Unit testing |
Java | Maven | 3.6.x | Build artifacts and execute tests |
NoSQL | Redis | 3.0.x | Data caching for fast reads |
NoSQL | MongoDB | 4.4 | Data store for nested schema |
Virtualization | Docker | 20.10.5 | Platform agnostic containerization |
OpenAPI | Swagger | 2 | REST API Documentation |
- Disk - 4 GB
- Memory - 4 GB
- Processor - 2 CPU
- Network - 80 MBps
- Operating System - Ubuntu 20.4 or Windows 10
- JDK - 11
- Python - 3.9
- Maven - 3.6.x
- Docker - 20.10.x
- Docker Compose - 1.28.x
- Open terminal or command prompt
- Go to the root folder of the project
sharenow-coding-challenge
containing the source code for all services - Execute
mvn clean package -e
at the root folder containing all the projects to download dependencies, build the artifacts and create docker images of the respective services - Execute
docker-compose -f docker-compose.infrastructure.yml up
at the root folder containing all the projects to start the infrastructure services for the microservice ecosystem - If prompted for
Continue with the new image? [yN]
during the docker-compose step, enter y - Browse to
http://<HOST_SYSTEM-IP>:8761
orhttp://localhost:8761
orhttp://172.27.0.6:8761
in a browser to see if EUREKA server is up or not - Browse to
http://<HOST_SYSTEM-IP>:8888/actuator/info
orhttp://localhost:8761/actuator/info
orhttp://172.27.0.6:8761/actuator/info
in a browser to see if configuration server is up or not which is denoted by a blank page and no errors - Wait for EUREKA and configuration server to become healthy
- Execute
docker-compose -f docker-compose.core.yml up
at the root folder containing all the projects to start the core microservices - If prompted for
Continue with the new image? [yN]
during the docker-compose step, enter y - Browse to
http://<HOST_SYSTEM-IP>:8761
orhttp://localhost:8761
orhttp://172.27.0.6:8761
in a browser to see if the all the services are available in EUREKA server or not - Access the Swagger documentation of individual core microservices viz., car, polygon, position in a browser to execute requests as desired over
http://<HOST-SYSTEM-IP>:8081/<SERVICE-NAME>/<SERVICE-CONTEXT-PATH>/swagger-ui.html
- Open terminal or command prompt
- Go to the root folder of the project
sharenow-coding-challenge
containing the source code for all services - Execute
docker-compose -f docker-compose.infrastructure.yml down
at the root folder containing all the projects to kill the containers of the infrastructure services for the microservice ecosystem - Execute
docker-compose -f docker-compose.core.yml down
at the root folder containing all the projects to kill the containers of the core microservices
- Search for a car by its VIN and get the strategic polygon details that it is currently mapped to
- Search for a strategic polygon by its id and get the list of cars that it currently contains
- Search for strategic polygons by a name apttern and collect all the cars that each matched strategic polygon contains
- Error reporting with codes and descriptive messages
Car to strategic polygon mapping ![Car to strategic polygon mapping](out/data/designs/sequence-get-car-with-enclosing-strategic-polygon/Get car by VIN and its enclosing strategic polygon.png)
Strategic polygon to cars mapping ![Strategic polygon to cars mapping](out/data/designs/sequence-get-strategic-polygon-with-enclosed-cars/Get strategic polygon by its Id and the cars it encloses.png)
Strategic polygons by name to their respective mappings of cars ![Strategic polygons by name to their respective mappings of cars](out/data/designs/sequence-get-strategic-polygons-and-their-enclosed-cars/Get strategic polygons with matching name and the cars each of it encloses.png)
SERVICE NAME | FUNCTIONALITY | TYPE |
---|---|---|
configuration-service | Centralized configuration store for all microservices | Maven Project |
naming-service | Service registration and discovery for all microservices by their name | Maven Project |
gateway-service | Single entry point to provided accessibility for all microservices by their API, routes request to appropriate microservices | Maven Project |
polling-service | Periodically refreshes live car locations for Stuttgart and puts them into the cache, Evicts cars using a custom least recently updated eviction policy | Maven Project |
car-service | Query for cars and their details from cache for Stuttgart | Maven Project |
polygon-service | Query strategic polygons and their details for Stuttgart | Maven Project |
position-service | Maps cars to its enclosing strategic polygon using its vin, Collects all cars present within a strategic polygon by its id | Maven Project |
cache-service | Stores live data for cars from Stuttgart and evicts data having TTL set against its key | Docker Image |
documentdb-store | Stores strategic polygons for Stuttgart and their details | Docker Image |
tracing-service | Trace requests across microservices for debugging | Docker Image |
car2godeveloper-service | Provides live locations of cars in Stuttgart | Docker Image |
- All business logic is written specifically for Stuttgart
- No two strategic polygon intersects
- Any car on the edge of a strategic polygon's boundary, will be considered within the polygon
- polling-service is expected to be a daemon service that is concerned with writing to a data store only, hence it doesn't need horizontal scaling but rather vertical scaling if at all required to be more performant
- JAVA_HOME and MAVEN_HOME is set on the host system
- car2godeveloper/api-for-coding-challenge has been treated as a black box with only documentation available to use it as required
- Cars can be queried either by their VIN or all the ones currently available at once
- Strategic polygons can be queried by their id or name or all available ones at once
- A car that is not within any of the strategic polygon will be deemed as unavailable
- A strategic polygon will report no cars available if it can't place any car within itself at any given point in time
- All other services except for polling-service should scale horizontally to keep up with dynamic load in favour of being high performant
- Swagger has only been enabled for services that define the core business logic viz., car, polygon, position
- Unit tests have been written to assert the business logic of core microservices viz., car, polygon, position
- polling-service is intended to be write intrinsic while car-service is intended to be read intrinsic through a distributed workflow spanning across two microservices and integrated using a cache (redis). This has been done to avoid bottle-neck and any single point of failure.
- Each microservice is a spring boot application following the pattern of controller, service and repository, where repository can be either a database or an external service as per the respective microservice's use case
- Scheduled service follows the pattern of input, process, and output like batch jobs
- Functional interfaces have been defined in each microservice to perform one off business logic
- All business specific exceptions are checked exceptions having a custom message and an enum based error code which in turn contains a prdefined application specific error code in the format
SNCC-<INITIALS-OF-SERVICE-NAME>-<INCREMENTING-NUMBER>
and its corresponding HTTP Status code - Each microservice has a REST webservice error handler that catches any business specific exception to translate them into appropriate error messages and HTTP status codes
- Sleuth and Zipkin has been added to each of the core microservices for the purpose of tracing distributed requests across multiple microservices
- Application specific configuration changes are loaded and propagated downstream in the order as follows: java system variables, bootstrap.properties, application-.properties in configuration server
- All services have been assigned static IPs when running as docker containers where the subnet has a capacity of accommodating 2^25 -1 machines for scalability
- The algorithm to place cars within strategic polygons by matching the name of strategic polygons, has a time complexity of O(nm) where m is the number of cars and n is the number of strategic polygons
- The algorithm to check whether a point lies within or exactly on the boundary of a strategic polygon , has a time complexity of O(n) where n is the number of vertices in the strategic polygon
- Configuration store for all services in configuration-service is chosen as embedded because of non public git restriction
SERVICE-NAME | API DOCUMENTATION URL |
---|---|
car-service | http://:8081/car-service/car/swagger-ui.html) |
polygon-service | http://:8081/polygon-service/polygon/swagger-ui.html) |
position-service | http://:8081/position-service/position/swagger-ui.html) |
- Implement circuit breaker for service resilience in conjunction with client side load balancing
- Block direct access to all microservices, except through gateway
- Enable security on all infrastructure services and core microservices
- Enable authentication of redis cache and mongodb database server
- Encrypt security credentials in configuration store
- Redis should be configured for master-slave where master is write concern and all slaves are read concerns with eventual consistency between them
- Synchronize bootstrap of infrastructure and core services of this project in docker-compose
- In the
scripts
folder under the root foldersharenow-coding-challenge
you will find the postman collection corresponding to all the REST APIS defined for each microservice in this entire project and the environment settings as well for the REST APIs. You can use it as well if needed. If you are using the environment settings for postman, update the value ofvirtual-host
variable to the IP of the host system where all the docker containers for this project are running
- If you are facing docker network issues while running the docker compose files, execute
docker system prune
to reset the networks - The docker image builds that take place via maven can create additional images that take up space in your file system but are not tagged with any name or tag because when you run
docker images
you will see there are images with as image name and image tag. Usedocker rmi <list of image ids>
to clear such orphan images - If you are facing issues in bring up mongodb docker container (documentdb-service) due to a permission error where /adata/db is locked within the container, change the host value of volume option under documentdb-service in docker-compose.infrastructure.yml file to an absolute path where you knwo that the system user you are currently logged in as, has permission ot read or write