Created
October 22, 2010 16:00
-
-
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.
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
''' | |
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 |
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
from django.conf.urls.defaults import * | |
urlpatterns = patterns('tracker.views', | |
url(r'^tracker/', 'empty'), | |
) |
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
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