Skip to content

Instantly share code, notes, and snippets.

@oubiwann
Created October 10, 2012 21:16
Show Gist options
  • Save oubiwann/3868462 to your computer and use it in GitHub Desktop.
Save oubiwann/3868462 to your computer and use it in GitHub Desktop.
Memcache, Twisted Templates, and the Klein Mirco-webframework
"""
A simple configuration file.
"""
cache = True
debug = True
import functools
import config, helper
def cache(routeFunction):
"""
A decorator for caching pages.
"""
@functools.wraps(routeFunction)
def wrapper(request):
"""
This wrapper needs to return something that klein knows how to render,
such as Twisted templates (page classes) or something that is
"flattenable" by Twisted template code (such as tags or strings).
"""
pageClass = routeFunction(request)
if not config.cache:
return pageClass()
return helper.MemCacheHelper(request, pageClass).getPage()
return wrapper
from twisted.internet import protocol, reactor
from twisted.protocols import memcache
from twisted.python import log
from twisted.web.template import flattenString
import config
class MemCacheHelper(object):
"""
"""
def __init__(self, request, pageClass):
self.request = request
self.pageClass = pageClass
self.memcache = None
self.key = ""
def setPage(self, page):
d = self.memcache.set(self.key, page)
d.addErrback(log.msg)
return page
def getOrFlattenPage(self, result):
flags, page = result
if page:
if config.debug:
log.msg("Cache hit; skipping page generation ...")
return page
if config.debug:
log.msg("No page in cache; getting and setting ...")
d = flattenString(self.request, self.pageClass())
d.addErrback(log.msg)
d.addCallback(self.setPage)
return d
def pokeMemCache(self, mem):
if not mem:
if config.debug:
log.msg("Cannot connect to memcache server!")
return self.pageClass()
self.memcache = mem
d = self.memcache.get(self.key)
d.addErrback(log.msg)
d.addCallback(self.getOrFlattenPage)
return d
def getPage(self):
"""
"""
# The key should uniquely identify renderable content, e.g., if you
# have a page that can only be rendered one way, then the URL should be
# fine. However, if that page will render differently per logged in
# user, for example, then you'd want to add a user id to the key as
# well. See the following for more information:
#
# * http://code.google.com/p/memcached/wiki/NewProgramming#Key_Usage
# * http://code.google.com/p/memcached/wiki/NewProgrammingTricks#Reducing_key_size
self.key = self.request.path
if config.debug:
log.msg("Generated key:", self.key)
client = protocol.ClientCreator(reactor, memcache.MemCacheProtocol)
d = client.connectTCP("localhost", memcache.DEFAULT_PORT)
d.addErrback(log.msg)
d.addCallback(self.pokeMemCache)
d.addErrback(log.msg)
return d
from twisted.web.template import Element
class BasePage(Element):
"""
Silly pase page.
"""
content = ""
def __init__(self):
Element.__init__(self, loader=self.content)
class TonsOfWorkPage(Element):
"""
Okay, so maybe not *tons* of work...
"""
content = "0100110100" * 1024
class LazyDoNothingPage(Element):
"""
This guy's sitting outside his dorm in boxes and flip-flops.
"""
content = "Man, whatever. I'm just gonna chill."
import klein
import pages
@klein.route("/expensive-page")
@pages.cache
def notcheap(request):
return pages.TonsOWorkPage
@klein.route("/lazy-page")
def cheap(request):
return pages.LazyDoNothingPage()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment