CacheCore
Dependency Invalidation
CacheCore

Dependency Invalidation

Cachecore's dependency system lets you tag cached responses with the data they depend on. When that data changes, invalidate the tag and all associated cache entries (L1 and L2) are deleted.

The problem

If you cache "Summarise contract #123" and the contract is later updated, the stale summary continues to be served until TTL expiry. TTL-based expiry alone is not sufficient for data-sensitive workloads.

How it works

  1. Tag at request time. Declare dependencies when making a cached request:
with cc.request_context(deps=[Dep("doc:contract-123", hash="v1")]):
    response = await openai.chat.completions.create(
        model="gpt-5.4-mini",
        messages=[{"role": "user", "content": "Summarise contract #123"}],
    )
  1. Cachecore stores the dep alongside the entry. The dep_id and expected_hash are written to a Redis set (cc:dep:keys:{dep_id}) that tracks which cache keys depend on this resource.

  2. Invalidate when data changes. Call invalidate with the dep ID and a new hash:

result = await cc.invalidate("doc:contract-123", new_hash="v2")
  1. Cachecore deletes all tagged entries. Both L1 (cc:l1:...) and L2 (vec:...) entries referencing this dep are removed from Redis.

Multiple dependencies per request

A single cache entry can declare multiple deps:

with cc.request_context(deps=[
    Dep("doc:contract-123"),
    Dep("user:tenant-456"),
]):
    response = await openai.chat.completions.create(...)

The entry is invalidated if any of its deps is invalidated.

Bulk invalidation

results = await cc.invalidate_many(
    dep_ids=["table:products", "table:prices"],
    new_hash="2024-03-15",
)
for r in results:
    print(r.dep_id, "ok" if r.ok else r.error)

Via HTTP:

curl -X POST https://api.cachecore.it/v1/invalidate \
  -H "Authorization: Bearer cc_live_xxxxx.eyJ..." \
  -d '{"dep_id": "table:products", "new_hash": "2024-03-15"}'

Expected hash validation

The hash parameter in Dep("doc:contract-123", hash="v1") is the data version at cache-write time. On subsequent cache lookups, if the current hash for that dep has been updated (via /v1/invalidate), the cached entry is rejected even before TTL expiry.

This enables version-aware caching:

Dep("doc:contract-123", hash=document.version)

# After an update:
await cc.invalidate("doc:contract-123", new_hash=document.new_version)

Automatic policy-version dep

Cachecore appends a cc:policy-version dep to every cache entry automatically. This allows global cache invalidation by rolling the policy version. See Namespaces for details.

Production patterns

See Invalidation Patterns for recipes covering webhooks, event-driven invalidation, batch updates, and bypass for write operations.