Build a CDN (13 scenes)
Scene 04 · TTL — origin tells the edge how long to trust the copy
max-age applies to every cache, including the browser; s-maxage overrides it for shared caches like the CDN — and TTL is what flips a cell from fresh to stale.
Previously

The user is now reaching a nearby POP — but how long does that POP hold the cached copy before checking origin again? The origin tells it via Cache-Control, and the dial that lets the CDN hold for a day while the browser holds for a minute is s-maxage.

Scene 04
TTL — origin tells the edge how long to trust the copy
Diagram
Top: an origin response headers panel showing the live Cache-Control directives. Below it, two parallel timeline lanes — BROWSER (uses max-age) and EDGE (uses s-maxage) — each with a cached cell that is green when fresh and gray when stale, plus a countdown bar ticking down to 0. Bottom: an origin RPS strip that stays at 0 while the edge cell is fresh and ticks up the moment it goes stale. **TTL** — time-to-live; how long a cached copy is considered fresh before it needs revalidation. **Cache-Control** — origin response header that sets cache lifetime; `max-age` applies to every cache including the browser; `s-maxage` overrides max-age for shared caches like the CDN.
ORIGIN RESPONSE HEADERS · read-onlyedited via scene controlsCache-Control: public, max-age=60, s-maxage=3600MAX-AGE · browser60s (1m)S-MAXAGE · edge / shared3600s (1.0h)PUBLICshared-cacheableBROWSERprivate cache · uses max-agemax-age = 60sFRESH/index.html01:00COUNTDOWNof 01:0001:00ticking down · serves from cache (no origin hit)EDGEshared cache · uses s-maxages-maxage = 3600sFRESH/index.html60:00COUNTDOWNof 60:0060:00ticking down · serves from cache (no origin hit)ORIGIN · requests in last 30sedge fresh · should stay near 00 rps
t = 0s · Both lanes fresh: every request is served from cache, origin RPS is zero.
A response just arrived at the POP with `Cache-Control: public, max-age=60, s-maxage=3600`. The EDGE cell shows 1:00:00 ticking, the BROWSER cell shows 1:00 ticking — both green. Watch the clock advance: the browser will turn gray well before the edge does.
Implementation
Cache.parseCacheControl(header, role)
shared caches override max-age with s-maxage; browsers ignore it
1def parseCacheControl(header, role):
2 d = parseDirectives(header) # k=v pairs
3 if 'no-store' in d:
4 return Lifetime(ttl=0, store=False)
5 max_age = int(d.get('max-age', 0))
6 s_maxage = d.get('s-maxage') # may be absent
7 if role == 'shared' and s_maxage is not None:
8 return Lifetime(ttl=int(s_maxage))
9 return Lifetime(ttl=max_age)
Cache.isFresh(cell, now)
the TTL countdown — fresh until age exceeds the lifetime
1def isFresh(cell, now):
2 if cell.lifetime.ttl == 0:
3 return False # born stale (e.g. max-age=0)
4 age = now - cell.created_at
5 return age < cell.lifetime.ttl
Cache.serve(request, role)
lookup, freshness check, hit-or-revalidate
1def serve(request, role):
2 cell = store.lookup(request.url)
3 if cell is None:
4 return forwardToOrigin(request) # MISS
5 if isFresh(cell, now()):
6 return cell.response # HIT
7 # stale: must revalidate before serving
8 return revalidate(cell, request)