Build a CDN (13 scenes)
Scene 07 · Purge — URL, surrogate key, or sledgehammer
Three purge flavors: URL (precise, slow at scale), surrogate-key (atomic, fast), zone-wide (sledgehammer that stampedes origin).
Previously

Purge is the escape hatch you reached for at the end of the last scene — but purging a copy in one POP doesn't help the other 299 POPs still serving it, so the question becomes WHICH POPs and WHICH entries one purge call actually invalidates.

Scene 07
Purge — URL, surrogate key, or sledgehammer
Diagram
A world map with 12 POPs; each POP holds a small grid of cached cells colored by surrogate-key tag (blue = product:42, orange = homepage, green = catalog, grey = other). The bottom panel offers three purge flavors: URL purge clears one cell per POP, surrogate-key purge clears every cell sharing the tag, zone-wide purge clears everything. After a deploy, you don't want to wait for TTL — you want to actively tell the cache to forget; that operation is called a purge. **purge** — invalidate cached entries across the CDN before their TTL expires. **surrogate key** — a tag the origin attaches to a response (Fastly term; Cloudflare calls them cache tags); one purge call invalidates every object sharing the tag. The propagation timeline shows p50 (~150 ms) and p99 (seconds) for the wave to reach all POPs; the origin RPS gauge spikes when zone-wide purge forces every POP to refill at once.
purge propagation · 12 POPsSURROGATE-KEY TAGSproduct:42homepagecatalogotherEDGE POPsus-west8/8us-east8/8us-centr…8/8sa-east8/8eu-west8/8eu-centr…8/8eu-north8/8me-centr…8/8af-south8/8ap-south8/8ap-south…8/8ap-east8/8PURGE CONTROLSURL or surrogate key/logo.pngURL purgeSurrogate-key purgeZone-wide purgePROPAGATION TIMELINEp50 · 150 msp99 · 320 msingressall POPsORIGIN RPSedge → originbaseline · 8ceiling · 1.2kNOW8steady-state · cache hits absorb loadACTIVE PURGEidle — pick a purge kind below
12 POPs, each with its own cached cells. Watch the purge wave radiate from the ingress POP.
A URL purge for /logo.png is fired from the Frankfurt ingress POP. Watch the wave ripple outward across all 12 POPs — only the /logo.png cell clears in each one. Origin RPS stays flat: each POP's next request will be a single miss.
Implementation
Edge.purge_handlers
three flavors — same control plane, different match rules
1def purge_url(url):
2 p = { kind: 'url', target: url }
3 broadcast_purge(p) # one cell per POP
4
5def purge_surrogate_key(tag):
6 p = { kind: 'surrogate', target: tag }
7 broadcast_purge(p) # every cell sharing tag
8
9def purge_zone():
10 p = { kind: 'zone', target: '*' }
11 broadcast_purge(p) # every cell, every POP
POP.apply_purge
what each POP does when the purge message arrives
1def apply_purge(p):
2 for cell in self.cache:
3 if matches(cell, p):
4 cell.invalidate() # next request = miss
5 ack(p.id, self.pop_id)
6
7def matches(cell, p):
8 if p.kind == 'zone': return True
9 if p.kind == 'url': return cell.url == p.target
10 if p.kind == 'surrogate': return p.target in cell.tags
Control.broadcast_purge
gossip the purge to every POP; track per-POP completion
1def broadcast_purge(p):
2 p.id = new_purge_id()
3 pending = set(all_pops)
4 for pop in all_pops:
5 pop.send(p) # bimodal multicast / gossip
6 while pending:
7 pop_id = wait_for_ack(p.id)
8 pending.remove(pop_id)
9 # p50 ~150 ms; p99 = slowest POP in the fleet
10 return { p50: ack_p50(), p99: ack_p99() }