The interview question: “A customer adds the last items to their cart. Hold them for 10 minutes so nobody else can buy them. If the customer never pays, the stock must come back by itself. How do you build it?”
The expected answer: don't change the stock and don't run a cleanup job. Save each hold with the time it expires, and compute the free stock when someone asks: available = stock − the holds that haven't expired yet. An expired hold simply stops being counted, so its stock comes back at the right second. A new hold that asks for more than is available gets 409.
Counting only what's still alive, on another value: coupons that are valid until a time.
coupons = [{"code": "SPRING", "until": 500}, {"code": "SUMMER", "until": 900}]
live = []
for coupon in coupons:
if coupon["until"] > now():
live.append(coupon["code"])
# at second 600, live is ["SUMMER"]
Time comes from now(), given in the starting code; the tests set it with an X-Test-Clock header. A hold lasts HOLD_SECONDS, 600 seconds. Product 6 has 4 in stock:
clock 1000 GET /products/6/available → 200 {"product_id": 6, "available": 4}
clock 1000 POST /holds {"cart_id": "cart-1", "product_id": 6, "quantity": 3}
→ 201 {"hold_id": 1, "cart_id": "cart-1", "product_id": 6, "quantity": 3, "expires_at": 1600}
clock 1000 GET /products/6/available → 200 {"product_id": 6, "available": 1}
clock 1100 POST /holds {"cart_id": "cart-2", "product_id": 6, "quantity": 2}
→ 409 {"error": "Not enough stock", "available": 1}
clock 1100 POST /holds {"cart_id": "cart-2", "product_id": 6, "quantity": 1}
→ 201 {"hold_id": 2, "cart_id": "cart-2", "product_id": 6, "quantity": 1, "expires_at": 1700}
clock 1599 GET /products/6/available → 200 {"product_id": 6, "available": 0}
clock 1600 GET /products/6/available → 200 {"product_id": 6, "available": 3}
clock 1600 POST /holds {"cart_id": "cart-3", "product_id": 6, "quantity": 3}
→ 201 {"hold_id": 3, "cart_id": "cart-3", "product_id": 6, "quantity": 3, "expires_at": 2200}
clock 1700 GET /products/6/available → 200 {"product_id": 6, "available": 1}
Your task: the holds table, both routes and the insert are written. Make available take off the holds that are still alive, and make POST /holds answer 409 with what's free when the cart asks for more.
Assignment
Follow the Coding Tutorial to count only live holds in available and to refuse a hold that is too big.
Hint
A hold is alive while its expires_at is later than now(): at exactly second 1600, cart-1's hold is gone. add_hold calls available too, so both routes count the same way.
Free plan: 30 tutor messages. PRO is unlimited.
