Cache

Table of contents

  1. Introduction
  2. Caching a value
  3. Caching JSON
  4. Building once for every worker
  5. Sharing a value across workers only
  6. Where values are kept
  7. Advanced
  8. 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


Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es