Cache
Table of contents
- Introduction
- Caching a value
- Caching JSON
- Building once for every worker
- Sharing a value across workers only
- Where values are kept
- Advanced
- See also
Introduction
Some things are slow to make and cheap to keep, such as a chart, a QR image or the numbers of a dashboard. The cache keeps them for a while under your feature’s own keys. It uses the product’s Redis when there is one and memory otherwise, and it never fails your request.
from splent_framework.cache import feature_cache
cache = feature_cache(__name__)
def chart(report_id):
image = cache.get(f"chart:{report_id}")
if image is None:
image = draw_chart(report_id)
cache.set(f"chart:{report_id}", image, ttl=3600)
return image
Caching a value
feature_cache(__name__) gives you the cache of your feature. Its keys live under <feature>:, so chart:7 of the reports feature is reports:chart:7 and never meets another feature’s.
get answers bytes, or None for a miss. set takes bytes or text, and ttl in seconds. Without a ttl the value stays until it is pushed out.
cache.set("greeting", "hola", ttl=60)
cache.get("greeting") # b"hola"
cache.delete("greeting")
Caching JSON
stats = cache.get_json("stats")
if stats is None:
stats = {"notes": Note.query.count(), "authors": authors_count()}
cache.set_json("stats", stats, ttl=300)
get_json and set_json take anything JSON can hold. A value that is not valid JSON reads as a miss.
Building once for every worker
if cache.add("rebuilding", "1", ttl=600):
try:
rebuild_dashboard()
finally:
cache.delete("rebuilding")
add sets a key only when it is not there, and tells you whether it did. With Redis that holds across every worker, so only one of them builds what all of them are missing.
If the cache cannot answer, add says True, so your code goes on and builds rather than waiting forever.
Sharing a value across workers only
cache = feature_cache(__name__, shared=True)
A dashboard every visitor sees should be the same in every worker. With shared=True the cache keeps values only in Redis. Without Redis it keeps nothing, and you make the value again each time. cache.available tells you which case you are in.
Where values are kept
| The product | Values live in |
|---|---|
Has a Redis cache (REDIS_CACHE_URL) |
Redis, shared by every worker |
| Has none | A dictionary in each process, 1,000 entries at most, the coldest out first |
Runs its tests (TESTING) |
Always the dictionary, so no test sees another’s values |
The feature that runs Redis sets REDIS_CACHE_URL.
Advanced
A Redis that does not answer is a miss when reading and a skipped write when writing. Each kind of failure is logged once, and your request goes on.
In tests, call
clear_memory()to forget what the process keeps.
See also
- Storage, for files you cannot make again.
- Fetching URLs