TTL — origin tells the edge how long to trust the copy

max-age applies to every cache; s-maxage overrides it for shared caches like the CDN; TTL is the countdown that flips a cached 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

  1. Watch
  2. Try it
  3. Predict
  4. Capture
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.
What to watch for

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.

Continue unlocks when the animation finishes.
Implementation

Highlighted lines are the ones running in the diagram right now.

Cache.parseCacheControl(header, role)
shared caches override max-age with s-maxage; browsers ignore it
def parseCacheControl(header, role):
d = parseDirectives(header) # k=v pairs
if 'no-store' in d:
return Lifetime(ttl=0, store=False)
max_age = int(d.get('max-age', 0))
s_maxage = d.get('s-maxage') # may be absent
if role == 'shared' and s_maxage is not None:
return Lifetime(ttl=int(s_maxage))
return Lifetime(ttl=max_age)
Cache.isFresh(cell, now)
the TTL countdown — fresh until age exceeds the lifetime
def isFresh(cell, now):
if cell.lifetime.ttl == 0:
return False # born stale (e.g. max-age=0)
age = now - cell.created_at
return age < cell.lifetime.ttl
Cache.serve(request, role)
lookup, freshness check, hit-or-revalidate
def serve(request, role):
cell = store.lookup(request.url)
if cell is None:
return forwardToOrigin(request) # MISS
if isFresh(cell, now()):
return cell.response # HIT
# stale: must revalidate before serving
return revalidate(cell, request)

Where this sits in Build a CDN

Scene 04 of 13, in the Freshness act — TTL, revalidation, stale-while-revalidate.. 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.

Up next. When the edge's copy goes stale it does not re-download the whole body — it asks origin a cheap question first.

All 13 scenes in Build a CDN · Every curriculum

Built with Arqly
Every scene in Build a CDN builds on the one before it.All 13 Build a CDN scenes