Skip to content

Instantly share code, notes, and snippets.

@andrewwatts
Created October 22, 2010 16:00
Show Gist options
  • Save andrewwatts/640804 to your computer and use it in GitHub Desktop.
Save andrewwatts/640804 to your computer and use it in GitHub Desktop.
Django middleware that sets a tracking id (fetched from a ticket server) as a cookie in the http response.
'''
Django middleware that sets a tracking id (fetched from a ticket server) as a
cookie in the http response.
This assumes you have setup a couple k/v stores as ticket servers and that
you know the key. For demonstration purposes only, here is how one might do it
with redis:
# start a redis server on default port (6379)
$ redis-server /usr/local/etc/redis.conf &> /dev/null &
# start a redis server on another port (16379)
$ redis-server /tmp/redis.16379.conf &> /dev/null &
# initialize the first service with integer 0
$ redis-cli
redis> select 1
OK
redis> set trackerid 0
OK
redis> quit
# initialize the second service with integer 1
$ redis-cli -p 16379
redis> select 1
OK
redis> set trackerid 1
OK
redis> quit
and then add this middleware to settings.MIDDLEWARE_CLASSES somewhere near the
top:
MIDDLEWARE_CLASSES = (
# middleware at the top of the stack
'middleware.TrackingMiddleware',
# middleware at the bottom of the stack
)
Finally start your server and test
$ manage.py runserver
$ curl -i http://localhost:8000/tracker/
$ ab -n 10000 -c 5 http://localhost:8000/tracker/
'''
import random
from collections import namedtuple
from datetime import datetime, timedelta
import redis
TicketServer = namedtuple('TicketServer', 'host, port, db')
ticket_servers = (
TicketServer(host='localhost', port=6379, db=1),
TicketServer(host='localhost', port=16379, db=1),
)
# format according to rc2109 - http://www.ietf.org/rfc/rfc2109.txt
# (Wdy, DD-Mon-YY HH:MM:SS GMT)
COOKIE_EXPIRES_FORMAT = '%a, %d-%b-%Y %H:%M:%S GMT'
def ring_generator(iterable):
'''simple generator that moves around the iterable'''
i = random.randint(0, len(iterable)-1)
while True:
yield iterable[i]
i = (i+1)%len(iterable)
class TrackingMiddleware(object):
'''
middleware that sets a tracking id (fetched from a ticket server) as a
cookie in the http response.
'''
def process_response(self, request, response):
value = request.COOKIES.get('trackerid', None)
if not value:
# assign a default value, just in-case all ticket servers are down
value = 0
# for high availability, loop over the ticket servers, starting
# at random location as determined by the ring generator
ticket_server_generator = ring_generator(ticket_servers)
for i in range(len(ticket_servers)):
try:
# get a ticket server and setup a client for it
ticket_server = ticket_server_generator.next()
ticket_server_client = redis.Redis(host=ticket_server.host,
port=ticket_server.port,
db=ticket_server.db)
# get next value by increasing it by number of servers
value = ticket_server_client.incr('trackerid', amount=len(ticket_servers))
except Exception, e:
import traceback
traceback.print_exc()
else:
break
# set the cookie and return the response
expires = (datetime.utcnow() + timedelta(days=365)).strftime(COOKIE_EXPIRES_FORMAT)
response.set_cookie('trackerid', value=value, expires=expires)
return response
from django.conf.urls.defaults import *
urlpatterns = patterns('tracker.views',
url(r'^tracker/', 'empty'),
)
from django.http import HttpResponse
def empty(request):
return HttpResponse('')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment