This repository has been archived by the owner on Aug 1, 2019. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Set up caching/etag for detail/archive views
- Loading branch information
tsauerwein
committed
Aug 11, 2016
1 parent
32f6dce
commit 57e1cea
Showing
14 changed files
with
429 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import logging | ||
|
||
import time | ||
from dogpile.cache import make_region | ||
from redis.connection import BlockingConnectionPool | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
# prefix for all cache keys | ||
KEY_PREFIX = 'c2corg_ui' | ||
|
||
# cache version (for production the current git revisions, for development | ||
# the git revision and a timestamp). | ||
CACHE_VERSION = None | ||
|
||
|
||
def create_region(name): | ||
return make_region( | ||
# prefix all keys (e.g. returns 'c2corg_ui_main:detail:3575-1-c796286') | ||
key_mangler=lambda key: '{0}:{1}:{2}'.format(KEY_PREFIX, name, key) | ||
) | ||
|
||
cache_document_detail = create_region('detail') | ||
cache_document_archive = create_region('archive') | ||
|
||
caches = [ | ||
cache_document_detail, | ||
cache_document_archive | ||
] | ||
|
||
|
||
def configure_caches(settings): | ||
global KEY_PREFIX | ||
global CACHE_VERSION | ||
KEY_PREFIX = settings['redis.cache_key_prefix'] | ||
|
||
# append a timestamp to the cache key when running in dev. mode | ||
# (to make sure that the cache values are invalidated when the dev. | ||
# server reloads when the code changes) | ||
cache_version = settings['cache_version'] | ||
if settings['cache_version_timestamp'] == 'True': | ||
cache_version = '{0}-{1}'.format(cache_version, int(time.time())) | ||
CACHE_VERSION = cache_version | ||
|
||
log.debug('Cache version {0}'.format(CACHE_VERSION)) | ||
log.debug('Cache Redis: {0}'.format(settings['redis.url'])) | ||
|
||
redis_pool = BlockingConnectionPool.from_url( | ||
settings['redis.url'], | ||
max_connections=int(settings['redis.cache_pool']), | ||
timeout=3, # 3 seconds (waiting for connection) | ||
socket_timeout=3 # 3 seconds (timeout on open socket) | ||
) | ||
|
||
for cache in caches: | ||
cache.configure( | ||
'dogpile.cache.redis', | ||
arguments={ | ||
'connection_pool': redis_pool, | ||
'distributed_lock': True, | ||
'lock_timeout': 5 # 5 seconds (dogpile lock) | ||
}, | ||
replace_existing_backend=True | ||
) | ||
|
||
|
||
class CachedPage(object): | ||
def __init__(self, api_cache_key, page_html): | ||
self.api_cache_key = api_cache_key | ||
self.page_html = page_html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import logging | ||
|
||
from pyramid.httpexceptions import HTTPNotModified | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
def etag_cache(request, etag_key): | ||
"""Use the HTTP Entity Tag cache for Browser side caching | ||
If a "If-None-Match" header is found, and equivalent to ``key``, | ||
then a ``304`` HTTP message will be returned with the ETag to tell | ||
the browser that it should use its current cache of the page. | ||
Otherwise, the ETag header will be added to the response headers. | ||
Suggested use is within a view like so: | ||
.. code-block:: python | ||
def view(request): | ||
etag_cache(request, key=1) | ||
return render('/splash.mako') | ||
.. note:: | ||
This works because etag_cache will raise an HTTPNotModified | ||
exception if the ETag received matches the key provided. | ||
Implementation adapted from: | ||
https://github.com/Pylons/pylons/blob/799c310/pylons/controllers/util.py#L148 # noqa | ||
""" | ||
# we are always using a weak ETag validator | ||
etag = 'W/"%s"' % etag_key | ||
etag_matcher = request.if_none_match | ||
|
||
if str(etag_key) in etag_matcher: | ||
headers = [ | ||
('ETag', etag) | ||
] | ||
log.debug("ETag match, returning 304 HTTP Not Modified Response") | ||
raise HTTPNotModified(headers=headers) | ||
else: | ||
request.response.headers['ETag'] = etag | ||
log.debug("ETag didn't match, returning response object") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.