Grace Periods
Grace periods let you serve stale data when the underlying source fails. Not unlike my middle-school lunch when New Jersey ran out of whatever crap they put between two pieces of “bread”.
The Problem
Section titled “The Problem”import { QueryCache, at, wild, MemoryAdapter } from '@t87s/core';
const cache = QueryCache({ schema: at('users', () => wild), adapter: new MemoryAdapter(), queries: (tags) => ({ getUser: (id: string) => ({ tags: [tags.users(id)], ttl: '10m', fn: () => db.users.findById(id), // What if DB is down? }), }),});from t87s import QueryCache, TagSchema, Wild, cachedfrom t87s.adapters import AsyncMemoryAdapter
class Tags(TagSchema): users: Wild[TagSchema]
class Cache(QueryCache[Tags]): @cached(Tags.users(), ttl="10m") async def get_user(self, id: str): return await db.users.find_by_id(id) # What if DB is down?
cache = Cache(adapter=AsyncMemoryAdapter())Without grace: if TTL expires and DB is down, users get an error, then a refund, then a lawsuit.
The Solution
Section titled “The Solution”import { QueryCache, at, wild, MemoryAdapter } from '@t87s/core';
const cache = QueryCache({ schema: at('users', () => wild), adapter: new MemoryAdapter(), queries: (tags) => ({ getUser: (id: string) => ({ tags: [tags.users(id)], ttl: '10m', grace: '6h', // Serve stale data for up to 6 hours if fn fails fn: () => db.users.findById(id), }), }),});from t87s import QueryCache, TagSchema, Wild, cachedfrom t87s.adapters import AsyncMemoryAdapter
class Tags(TagSchema): users: Wild[TagSchema]
class Cache(QueryCache[Tags]): @cached(Tags.users(), ttl="10m", grace="6h") # Serve stale for up to 6 hours if fn fails async def get_user(self, id: str): return await db.users.find_by_id(id)
cache = Cache(adapter=AsyncMemoryAdapter())With grace: when TTL expires, t87s tries to refresh. If that fails and we have stale data within the grace period, we hold our nose and serve the stale data while retrying in the background.