FREE STUDY NOTES · AI-200

Cache-aside, write-through and invalidation with Azure Managed Redis

The main Redis caching patterns, how to expire and invalidate entries, and the trade-offs of each.

From Ultra Transcenders AI-200 by Tony Rough (publishing soon)

Redis doesn’t keep itself in step with your database; the application (or a supporting process) decides when to load, update and invalidate cached data. Choosing the right caching pattern is about how much staleness the data can tolerate and how much write-path complexity you will accept.

Pattern How it works Freshness after a write Good fit
Cache-aside (lazy loading) Read cache; on a miss read the database, populate the cache with a TTL. On update, write the database then delete the key A reader can briefly see a miss or stale data until the next read repopulates Read-heavy data that tolerates short staleness, such as a product catalogue
Reference-data prefetching Load small, stable data at start-up and refresh it when the source changes; often no TTL Warm on every read once refreshed Categories, lookup tables, configuration
Write-through Update the database and the cache in the same operation; return only after both succeed Readers see the new value immediately Read-heavy paths that need read-after-write freshness, such as prices
Event-driven invalidation Writers append change events (for example to a Redis stream); consumers update or delete cached entries As fast as events are processed; survives consumer restarts Derived values such as order status projections
Session and state offload Transient state lives only in the cache Not applicable Carts, sessions, agent short-term memory

Cache-aside in Python

The cache is an optimisation, never the source of truth. This sketch follows the Learn pattern: Figure 9.1 shows the read path and the order of operations on an update.

A sequence diagram with the Redis cache, the app and the database. On a read, the app gets the key from the cache. On a hit it uses the value. On a miss it reads the item from the database and sets the key with a TTL. On an update, the app writes the database first and then deletes the cache key.
Figure 9.1: Cache-aside reads and invalidation on update
CACHE_TTL_SECONDS = 300

def get_product(product_id: int) -> dict | None:
    key = f"product:{product_id}"
    cached = r.get(key)
    if cached is not None:                    # cache hit
        return json.loads(cached)
    product = load_product_from_db(product_id)  # cache miss
    if product is not None:                   # avoid caching null values
        r.set(key, json.dumps(product), ex=CACHE_TTL_SECONDS)
    return product

def update_product(product: dict) -> None:
    save_product_to_db(product)               # 1. update the source of truth
    r.delete(f"product:{product['id']}")      # 2. then invalidate

Invalidation and consistency rules

Common trap: Invalidating the cache entry before writing to the database “to be safe” - that ordering opens a window where a concurrent reader caches the old value again; write the database first, then delete the key.

Common trap: Choosing cache-aside when users must see their own update immediately - cache-aside can serve a miss or stale value right after a write; use write-through for read-after-write freshness.

Get the whole book

This note is one section of Ultra Transcenders AI-200: Developing AI Cloud Solutions on Azure, an independent study guide that explains every topic the exam covers by technology, with comparison tables, diagrams and the common traps, plus a glossary linked to Microsoft Learn.

Amazon.co.ukKindle: coming soonPaperback: coming soon
Amazon.comKindle: coming soonPaperback: coming soon

Publishing soon on Amazon in Kindle and paperback editions.

About the book · AI-200 terms in the glossary · All AI-200 study notes

More AI-200 study notes