# TTLs, Refresh-Ahead and Negative Caching — Caching Strategies & CDN Design

Source: https://www.skillbyai.com/en/caching-strategies/p-ttl

> Choose TTLs deliberately and refresh hot data before it expires.

## How long should data live?

A **TTL** bounds staleness: after it expires, the next read reloads. Choose TTLs from business tolerance, not habit: exchange rates might accept 60 seconds, product descriptions an hour, a country list a day. Longer TTLs raise the hit ratio; shorter TTLs reduce staleness. Explicit invalidation lets you use long TTLs safely, with the TTL acting as a safety net if an invalidation is missed. **Refresh-ahead** reloads popular keys **before** they expire, in the background, so users never wait on a miss for hot data. **Negative caching** stores the fact that something does **not** exist ("no product with id 999") for a short time, so repeated lookups for missing keys do not hit the database every time; keep these TTLs short so newly created items appear quickly. Add a little random **jitter** to TTLs so keys created together do not all expire together.

## TTL with jitter and negative caching

A sentinel value records "not found" briefly.

```python
import json, random

NOT_FOUND = "__none__"

def ttl(base_seconds, jitter=0.1):
    return int(base_seconds * random.uniform(1 - jitter, 1 + jitter))

def get_user(user_id):
    key = f"user:v1:{user_id}"
    cached = redis.get(key)
    if cached == NOT_FOUND:
        return None                               # cached miss
    if cached is not None:
        return json.loads(cached)
    user = db.find_user(user_id)
    if user is None:
        redis.set(key, NOT_FOUND, ex=60)          # short negative TTL
        return None
    redis.set(key, json.dumps(user), ex=ttl(3600))
    return user
```

## A TTL is a promise about staleness

Write the TTL next to the business rule it satisfies, for example "prices may be up to 5 minutes old on listing pages; checkout always reads the database". It stops TTLs from being tweaked randomly.

**Quiz:** What problem does negative caching solve?

- [x] Repeated lookups for keys that do not exist hitting the database every time
- [ ] Values that are too large
- [ ] Keys that never expire
- [ ] Encrypting cached data

*Answer:* Repeated lookups for keys that do not exist hitting the database every time. Caching "not found" briefly protects the origin from repeated misses on absent keys.
