Welcome to the Parcel-simulator app. In the following sections you will get idea about the whole system in brief:
You can run the application by cloning this to your local machine or directly from Docker image.
The following sections will guide you to install the application:
If you want to test the application by only running the Docker containers, you can follow the steps below:
- Pull Redis Docker image:
docker pull redis:7-alpine
- Run the Redis image:
docker run --name redis --net=host -d redis:7-alpine
- Pull the application image:
docker pull piyush1146115/parcel:latest
- Run the application image:
docker run --name parcel-simulator --net=host -d piyush1146115/parcel:latest
- Clone the repository locally using git
- Change your current directory to the location of the project:
cd ./../parcel
Run Docker compose file:
docker compose up -d
This above steps should complete your installation.
N.B: Both of the above process assumes that Docker client is installed on your local machine
Here are some demo request of the server:
- Place order for customer with ID 11 (Authorized Customer)
curl localhost:8090/api/v1/parcel/11 -X POST -H "Content-Type: application/json" -d '{"receiver_name":"xyz", "receiver_number":"0131234131", "pickup_latitude":37.7749,"pickup_longitude":-122.4313,"dropoff_latitude":37.7886,"dropoff_longitude":-122.4314}'
Sample response:
{"order_id":1678341228942000002,"success":true}
- Place order for customer with ID 16 (Unauthorized)
curl localhost:8090/api/v1/parcel/16 -X POST -H "Content-Type: application/json" -d '{"receiver_name":"xyz", "receiver_number":"0131234131", "pickup_latitude":37.7749,"pickup_longitude":-122.4313,"dropoff_latitude":37.7886,"dropoff_longitude":-122.4314}'
Sample response:
No authorized customer found with id: 16
- Ping the homepage
curl localhost:8090
Sample response:
Welcome to the Homepage of parcel simulator!
- Get the current status of a Rider with ID 5
curl localhost:8090/api/v1/rider/status/5
Sample response: {"rider_id":5,"rider_status":"Available"}
- Get the current status of a Rider with ID 5
curl localhost:8090/api/v1/rider/location/6
Sample response: {"rider_id":6,"rider_latitude":37.7749,"rider_longitude":-122.4191}
- Get the current status of the order with ID 1678341228942000002 (Valid Order Id)
curl localhost:8090/api/v1/order/status/1678341228942000002
Sample response:
{"order_id":1678345319223000002,"order_status":"Accepted"}
{"order_id":1678345319223000002,"order_status":"Searching Rider"}
- The API will receive a new order request and response with a unique order ID
- The API will send events to the order processing task queue and Order status tracking queue
- The Order processing service will process the order requests asynchronously
- The Order processing service will find a nearest rider for the request based on availability
- If there is no available rider, then send another requeue event to the order processing task
- Rider service will send a request to the Location service to track available Riders location
- The Location service will update the current location to the cache
- Order Processing service will update the oder status in the cache
- Order Status Queue will get updated status from the cache periodically
- Order Status Queue will send event to the notification service
- The Notification service will send notification to the users
Here, we are going to look at some implementation details
- Each New parcel creation API call is responded with a unique order ID based on current timestamp
- The server saves the order ID in orders list and send an event to order processing queue and order status tracking queue
- The order status queue periodically checks for order status by corresponding orderID and check if order completed
- The order processing queue process rest of the tasks related to order and update the records
We have implemented a Redis Queue which acts like a message broker. It runs some concurrent workers to process works concurrently. We have used this queue to track order status, update order status, rider status etc. In the backend, we used Asynq library. The following image depicts how Asynq workers work under the hood.
In the real world system, there should be separate microservices for updating order status
and Rider's current location. However, for fast development we stayed in the
monolith approach. We have mock the location update service and order status service with time.Ticker
and goroutine in Golang.
We have implemented two separate functions those will run concurrently and update Rider's location and order status.
We have assumed that we already have a set of rider and user information to our
service. Again, for going fast we mocked the database with some in-memory json arrays.
However, we will move into Postgres
as permanent data storage and Redis
as cache data
storage in near future. For reference, we have designed a DB Schema
like the following.