-User can see the price of an item in the vending machine
-User can buy an item in a vending machine and vending machine processes payment
-vending machine updates inventory status in system when inventory is sold and also when it gets more inventory
Getting price of item should be low-latency
Payment should be consistent and secure
Inventory should be consistent but item price should be available
System can handle hot times like after lunch where might get more traffic
Certain areas have more vending machines than others
System can handle the huge traffic of requests
If there are approximately 5 million vending machines in the US each with around 30 to 50 products so about 250 million inventory to keep track of and 5 million vending machines
in High traffic areas have 300 transactions
so that means per day the machines in high traffic areas are having 450 million transactions
the other 70% of machines are having 175 million transactions
for item updates if we have 500 types of items and 5 million vending machines one a month we will get over a billion requests for item updates
GET /item
{gets item price}
POST /purchase
{machine_id, inventory_id, payment information, price_id}
POST /inventory {machine_id, item_id}
Machines
primary_key
coordinates
Items
primary_key
name
price
other_info
inventory
primary_key
item_id
machine_id
status: available| pending | sold
Purchases
primary_key
machine_id
item_id
payment_info
price
We want to index machines by area -> increase in concentration of indices for hot areas (basically if there are a lot more machines in an area index more heavily)
Inventory and Purchases we want to index by machine
Items and machines can most definitely be a SQL database due to being read heavy, Inventory and Purchases need to be consistent so that can be SQL
We will use Postgres for this
Due to the high traffic these databases will be read a lot so data reading must be efficient and will need to be indexed well
Getting item price is fairly straightforward, the machine sends a request which is added to a queue (due to the traffic of machines). Due to the monthly update of prices while this process does have heavy traffic it also does not happen very often so this should be fine, we use a cache to help with this process by caching the most commonly read items
Our Payment API works by a service that receives requests (there is a queue before), first it checks that the inventory for that machine is valid (i.e. available inventory of that item in that machine) and sets it to "pending" along with locking it. If there is not a valid inventory it returns and error to the client, otherwise it takes the payment information of the user and goes to the payment service, upon confirmation the payment went through it returns the confirmation to the user, sets the inventory to "sold" and then releases the lock, it asynchronously updates the purchases db with the transaction that just occured.
Adding inventory is straightforward, a service goes to the inventory DB and adds a inventory with the appropriate machine item and price.
GET item price -> request and item_id added to queue -> when read by service gets the item price from the cache, if not in cache goes to database -> this price is returned to the client
POST /purchase -> checks if inventory exists in machine -> if false returns error -> else locks the inventory and then sends payment information to the payment service -> if payment is successful updates the inventory db and returns the successful payment to the client -> while doing that also updates the purchase db with the purchase information
POST /inventory -> goes to service -> adds inventory to the inventoryDB -> returns rejection or failure
For the sake of scalability the payment, purchase item and inventory services all must be horizontally scalable
The lock can use a Redis TTL lock
We need queues for the services as there is a massive amount of traffic
By having the item prices updated once a month we can have situations where the price in the purchases are complicated to keep updated with spontaneous price changes, this assumes that is very uncommon
Having purchases update async can be a bit risky if something happens and purchase isn't properly updated or can be behind the purchase being made but it is more important that the purchase process is done quickly for the users.
Failures can be handled by the services -> traffic is high density areas means that if some services go down there could be strain on the ones who are left
A way for items to give real time updates to the machines