Code
memcached
# --- Read-through cache (cache-aside) ---
def get_user(user_id):
key = f"user:{user_id}"
val = mc.get(key)
if val is None: # cache miss
val = db.query("SELECT ...", user_id)
mc.set(key, json.dumps(val), expire=300) # 5 min
return json.loads(val)
# --- Write-through: update cache when DB changes ---
def update_user(user_id, data):
db.update("users", user_id, data)
mc.set(f"user:{user_id}", json.dumps(data), expire=300)
# OR invalidate: mc.delete(f"user:{user_id}")
# --- Session storage (with gat to extend on access) ---
def session_read(sid):
return mc.gat(sid, 1800) # read + extend ttl to 30min
def session_write(sid, data):
mc.set(sid, data, expire=1800)
# --- Lock with add (atomic) ---
def with_lock(key, ttl, fn):
token = uuid4().hex
if mc.add(f"lock:{key}", token, expire=ttl):
try:
return fn()
finally:
# release only if we still own the lock
cur, cas = mc.gets(f"lock:{key}")
if cur == token:
mc.cas(f"lock:{key}", b"", cas, expire=1)
else:
raise LockedError()
# --- Counter (rate limit) ---
def rate_limit(user_id, limit=100, window=60):
key = f"rl:{user_id}"
n = mc.incr(key, 1)
if n == 1:
mc.set(key, 1, expire=window) # set ttl on first hit
return n <= limit