Requirements
Functional Requirements:
- Allow reservation of a parking spot.
- Process payment for the reservation.
- Enable parking of a car in the reserved spot.
- Support early departure before reservation time expires.
- Gate check-in/out.
- Handle no show.
Non-Functional Requirements:
- High Availability- make sure our system is highly availably with 99.99% uptime in terms of services
- Latency - The payment process and parking acklodgement request should have low latency
- Reliability- THe system should calculate correct time and check the fare
- Security- The customer data and payment should be secure
- Consistency- System should be having a strong Consistency with payment and booking
- Systsem should handle peak request in scaling too, High scalability
API Design
Define the APIs expected from the system. This is your chance to analyze and define the read and write paths so that you can come up with the high-level design...
/reserveSpot{ vehicleNumber, start time, paymentMode , amount,curr, vehicleType?}
/getPrices{vehicleType,Location}
/payment/id/{reservationId}
/checkIn{reservationId,vehicleId,startime}
/checkout{{reservationId,vehicleId,startime}
High-Level Design
Describe the overall system architecture. Identify the main components needed to solve the problem end-to-end. Use the diagramming tool to create a block diagram.
Okay, so let me start with the client. The client can talk to the reservation service and that will be via API gateway. So their API gateway will be focusing on authorization, routing, and all the requests on a scalable platform. And the reservation service will have only a few responsibilities to take the client details, the start time, and the vehicle type. And then for the payments, we will go with the transaction service. The transaction service is responsible for talking to the payment provider and getting the payment details. Once the payment details are done, it will call the reservation service and that can actually put two things. It can first store the data into RDBMS store at the same point of time. It will store the data into Redis cache and onto the event bus. Event bus is for the analytical part. However, it is not covered in this scope, but still we want to keep it. Now, second thing goes is that Redis cache use. The Redis cache will be used to kind of prevent two things, dual booking, like if the reservation gets stopped in between, the Redis cache will be talking to, we will have a retry mechanism which can actually talk to the Redis cache and get the details of the booking. The client, we will have a distinct key. We can use the UUID for it. And the both transaction service and the reservation service will talk to the Redis cache and kind of have this dual order check. And this is where we will stop using the item potent key of the payment or reservation ID. As far as the IoT gate services will be talking to check-in checkout time, we will have, either we can have check-in checkout service or just IoT gate devices, which can actually client can scan the card and then we will check it out. We will keep it to the event bus, which can go into the analytical stores. We can also maybe have another event which can check if any reservation service is not shown, that can be captured by our analytics engine.
So we will do the rate limiting for this via a normal sliding window-based technique because I think we can have a particular user to kind of take this service. Also, the authorization for incoming requests will be done via a JWT token, and at the same point of time, we can have an OAuth. So JWT session will be there for 15 minutes, while the refresh token, we can have it for seven days. And whenever the site, like the user credentials drops, we can actually do it. Now, we have also made sure of...Now let's talk about client journey. The client will go account to the platform using the IoT gate devices, and it will make a reservation so that the moment it will do a check-in, the reservation service will be kicking. And we will fire the event into the transaction service. The transaction service will take care of the payment. Once the payment is successful, the reservation service will send an alert to the IoT gate that it can open the device and start the account billing the customer. At the same point of time, if the customer's payment ID got stopped in between, we will use the same payment ID to kind of get the same payment ID and same reservation ID to get the request. We will retry. And we can, yeah, so that's how it will, while coming back, it will, the IoT gate will go with the reservation ID. Reservation ID will calculate the customer's data and the amount he needed to pay. And once the customer pay the amount, either we can do prepaid or post-paid, at that time, we'll open the transaction ID for it.
we will have a TTL for the Redis cache so that our stale cache will have the cache invalidations. We can always go with once the reservation is active, we will store the value and if the reservation goes down, we will just store that information into Redis cache as well as Cassandra DB for further steps. Now coming to the authoritative commit, it's like once we go and confirm the particular case, like once the particular check is done, we will just store that particular information and we will also make sure that the DB entry and the event bus entry should handle on like outbox pattern where both data and entry should be one where and then the event bus will take the value from the outbox data.
We will have an idempotency check on each reservation in transaction service, and that can be done by the unique UUID key, and for all the idempotency, we will store the responses with the key, and that's how we will be able to maintain the strong consistency.
Detailed Component Design
Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.
The client can talk to the reservation service and that will be via API gateway. So their API gateway will be focusing on authorization, routing, and all the requests on a scalable platform. And the reservation service will have only a few responsibilities to take the client details, the start time, and the vehicle type. And then for the payments, we will go with the transaction service. The transaction service is responsible for talking to the payment provider and getting the payment details. Once the payment details are done, it will call the reservation service and that can actually put two things. It can first store the data into RDBMS store at the same point of time. It will store the data into Redis cache and onto the event bus. Event bus is for the analytical part. However, it is not covered in this scope, but still we want to keep it. Now, second thing goes is that Redis cache use. The Redis cache will be used to kind of prevent two things, dual booking, like if the reservation gets stopped in between, the Redis cache will be talking to, we will have a retry mechanism which can actually talk to the Redis cache and get the details of the booking. The client, we will have a distinct key. We can use the UUID for it. And the both transaction service and the reservation service will talk to the Redis cache and kind of have this dual order check. And this is where we will stop using the item potent key of the payment or reservation ID. As far as the IoT gate services will be talking to check-in checkout time, we will have, either we can have check-in checkout service or just IoT gate devices, which can actually client can scan the card and then we will check it out. We will keep it to the event bus, which can go into the analytical stores. We can also maybe have another event which can check if any reservation service is not shown, that can be captured by our analytics engine.
So we will do the rate limiting for this via a normal sliding window-based technique because I think we can have a particular user to kind of take this service. Also, the authorization for incoming requests will be done via a JWT token, and at the same point of time, we can have an OAuth. So JWT session will be there for 15 minutes, while the refresh token, we can have it for seven days. And whenever the site, like the user credentials drops, we can actually do it. Now, we have also made sure of...Now let's talk about client journey. The client will go account to the platform using the IoT gate devices, and it will make a reservation so that the moment it will do a check-in, the reservation service will be kicking. And we will fire the event into the transaction service. The transaction service will take care of the payment. Once the payment is successful, the reservation service will send an alert to the IoT gate that it can open the device and start the account billing the customer. At the same point of time, if the customer's payment ID got stopped in between, we will use the same payment ID to kind of get the same payment ID and same reservation ID to get the request. We will retry. And we can, yeah, so that's how it will, while coming back, it will, the IoT gate will go with the reservation ID. Reservation ID will calculate the customer's data and the amount he needed to pay. And once the customer pay the amount, either we can do prepaid or post-paid, at that time, we'll open the transaction ID for it.
we will have a TTL for the Redis cache so that our stale cache will have the cache invalidations. We can always go with once the reservation is active, we will store the value and if the reservation goes down, we will just store that information into Redis cache as well as Cassandra DB for further steps. Now coming to the authoritative commit, it's like once we go and confirm the particular case, like once the particular check is done, we will just store that particular information and we will also make sure that the DB entry and the event bus entry should handle on like outbox pattern where both data and entry should be one where and then the event bus will take the value from the outbox data.
We will have an idempotency check on each reservation in transaction service, and that can be done by the unique UUID key, and for all the idempotency, we will store the responses with the key, and that's how we will be able to maintain the strong consistency.
How will you handle conflicts when two users reserve the same spot?
For each parking spot, what we will do is we will actually have a parking spot ID and we will do a soft hold whenever the user clicks on it so that the other user cannot invoke it. We can use distributed locking where a redis-based lock can be done, where we can use the quorum-based locking so that we will be able to stop this from double booking.
Hot Iot Surges
We would implement rate limiting for the user on the high days so that each particular gateway device can now handle only those service. If the rate limiting is down or something like that, we will just have a hard manual override of suppose 100 requests per device. And we will also implement backpressure so that if in case of traffic burst, we can make them into a backpressure queue so that it can be taken later.
expiration of holds
we would, first of all, whenever the hold is expired, we will just have a 15 minutes timer. So after that, we will automatically see if the particular transaction has been done, then we will just do the from hold to booked. If not, we will just like there will be a see, this is how we will be checking it so that we can change it again. And if it's about the booking service, once the booking has been done, we can just mark it to from available again from the completed booking.
overlapping reservations
To maintain overlapping reservation, we will go with the pessimistic locking and with the soft hold, as I mentioned above, so that once a user comes, we will be able to do it and we will use distributed locking for that using Redis Redlock to kind of prevent it. And one of the examples is Redis Redlock, but yeah.