+ # Smallest limit wins
+ limit = min(self.limit, global_limit)
+
+ # Latest max age wins. Note that either could be None, but that's
+ # fine, because None is less than everything else
+ max_age = max(self.max_age, global_max_age)
+
+ return self._poll(limit, max_age)
+
+ def _poll(self, limit, max_age):
+ """Implementation of polling for updates. Must return an iterable.
+ Each element should be an object with ``source`` and ``time``
+ properties. A namedtuple works well.
+ """
+ raise NotImplementedError
+
+class CachedSource(Source):
+ """Supports caching a source's updates in memcache.
+
+ On the surface, this functions just like any other ``Source``. Calling
+ ``poll`` still returns a list of updates. However, ``poll`` does not call
+ your ``_poll``; instead, your implementation is called by the spline cron,
+ and the results are cached. ``poll`` then returns the contents of the
+ cache.
+
+ You must define a ``_cache_key`` method that returns a key uniquely
+ identifying this object. Your key will be combined with the class name, so
+ it only needs to be unique for that source, not globally.
+
+ You may also override ``poll_frequency``, the number of minutes between
+ pollings. By default, this is a rather conservative 60.
+
+ Note that it may take up to a minute after server startup for updates
+ from a cached source to appear.
+ """
+
+ poll_frequency = 60
+
+ def cache_key(self):
+ return repr(type(self)) + ':' + self._cache_key()
+
+ def _cache_key(self):