Problem
/predict re-runs vectorization + inference + enrichment on every call, including for identical repeated inputs (common in bulk/retry traffic). There is no caching, so duplicate work scales linearly with request volume.
Proposed solution
Add an in-process, thread-safe cache keyed by the normalized input and the current serving model version, so identical inputs return instantly and a model reload can never serve stale predictions.
Scope
- A prediction-cache module (
backend/predict_cache.py): a bounded TTL + LRU cache (size and TTL from settings), keyed by sha256(normalized_text) (reusing utils/text_normalizer) combined with serving_state.version and any prediction options; thread-safe.
- In
/predict: look up before inference and store after; bypass on Cache-Control: no-cache or ?fresh=1; set an X-Cache: HIT|MISS response header; expose hit/miss/size (via a small /cache-stats or folded into /model-info).
- A README + OpenAPI note; regression coverage (hit/miss, TTL expiry, invalidation across a version bump, bypass header).
Why it's safe
Namespacing the key by serving_state.version means a hot-swap (#980) transparently invalidates the cache — no stale model outputs. Success/response shapes are unchanged; X-Cache is purely additive.
Acceptance criteria
- Repeated identical input yields
X-Cache: HIT and an identical body.
- A model reload flips subsequent lookups to
MISS (no stale results).
- The cache is bounded (evicts by size and TTL) and never grows unbounded.
Out of scope
Distributed/Redis-backed caching; caching non-idempotent endpoints.
Problem
/predictre-runs vectorization + inference + enrichment on every call, including for identical repeated inputs (common in bulk/retry traffic). There is no caching, so duplicate work scales linearly with request volume.Proposed solution
Add an in-process, thread-safe cache keyed by the normalized input and the current serving model version, so identical inputs return instantly and a model reload can never serve stale predictions.
Scope
backend/predict_cache.py): a bounded TTL + LRU cache (size and TTL from settings), keyed bysha256(normalized_text)(reusingutils/text_normalizer) combined withserving_state.versionand any prediction options; thread-safe./predict: look up before inference and store after; bypass onCache-Control: no-cacheor?fresh=1; set anX-Cache: HIT|MISSresponse header; expose hit/miss/size (via a small/cache-statsor folded into/model-info).Why it's safe
Namespacing the key by
serving_state.versionmeans a hot-swap (#980) transparently invalidates the cache — no stale model outputs. Success/response shapes are unchanged;X-Cacheis purely additive.Acceptance criteria
X-Cache: HITand an identical body.MISS(no stale results).Out of scope
Distributed/Redis-backed caching; caching non-idempotent endpoints.