URL Shortener
Expiry without slowing the redirect
Before you start
- Open lesson
Requirements
Each worked system starts from a scoped list of verbs and numbers.
Why it matters
A link that dies at time 100 must stop redirecting at that boundary even if it was popular a moment earlier. Cleanup can run late, and an owner still needs an efficient list of live links, so deletion timing cannot define visitor behavior. A cached response for x7 must return 404 at time 120 and must never preserve a 301 past expiry.
Example
Design an expiring link
Links die at a timestamp. Visitors after that see a 404. Owners can see which of their links are still live.
- Input
- rows = {"x7": {"url": "/sale", "expires": 100}}, cache = {}, reads = [["x7", 10], ["x7", 50], ["x7", 120], ["q2", 5]]
- Output
- [301, 301, 404, 404]
Mental model
The idea
Keep one example in view
Design an expiring link
rows = {"x7": {"url": "/sale", "expires": 100}}, cache = {}, reads = [["x7", 10], ["x7", 50], ["x7", 120], ["q2", 5]]→[301, 301, 404, 404]
Keep this exact scenario and its constraint in view while you build the model.
For x7 with expires_at = 100, compare that timestamp on every redirect, including cache hits; return 404 and evict x7 at time 120, while a background job later deletes the row in batches.
The x7 row stores expires_at = 100. Reads at 10 and 50 compare that value even when x7 comes from the cache and return 301. At 120, the same check returns 404 and removes x7. Give the cache entry an absolute expiry of 100, or TTL = 100 − now, but still check the row timestamp.
A periodic worker deletes expired rows in batches because physical cleanup does not determine correctness. Index (owner_id, expires_at) so an owner can range-scan only links whose expiry is still ahead. The extra timestamp check is cheap; the index and cleanup job add storage and write work.
Visual anchor
Design an expiring link
reads (code @ time)
Pro
The rest of this is on Pro
The idea above is free. The walkthrough, the cost, and the practice are on Pro.