query_cache

exception gratipay.utils.query_cache.FormattingError[source]

Represent a problem with a format callable.

class gratipay.utils.query_cache.Entry(timestamp=0, lock=None, result=None)[source]

An entry in a QueryCache.

class gratipay.utils.query_cache.QueryCache(db, threshold=5, threshold_prune=60)[source]

Implement a caching SQL post-processor.

Instances of this object are callables that take two or more arguments. The first argument is a callback function; subsequent arguments are strings of SQL. The callback function will be given one result set per SQL query, and in the same order. These result sets are lists of dictionaries. The callback function may return any Python data type; this is the query result, post-processed for your application.

The results of the callback are cached for <self.threshold> seconds (default: 5), keyed to the given SQL queries. NB: the cache is not keyed to the callback function, so cache entries with different callbacks will collide when operating on identical SQL queries. In this case cache entries can be differentiated by adding comments to the SQL statements.

This so-called micro-caching helps greatly when under load, while keeping pages more or less fresh. For relatively static page elements like navigation, the time could certainly be extended. But even for page elements which are supposed to seem completely dynamic – different for each page load – you can profitably use this object with a low cache setting (1 or 2 seconds): the page will appear dynamic to any given user, but 100 requests in the same second will only result in one database call.

This object also features a pruning thread, which removes stale cache entries on a more relaxed schedule (default: 60 seconds). It keeps the cache clean without interfering too much with actual usage.

If the actual database call or the formatting callback raise an Exception, then that is cached as well, and will be raised on further calls until the cache expires as usual.

And yes, Virginia, QueryCache is thread-safe (as long as you don’t invoke the same instance again within your formatting callback).

prune()[source]

Periodically remove any stale queries in our cache.