1

I've got strange issue - I hope someone run similar problem before.

I'm trying to cache content from different subdomains connected via wildcard to my django application 'example.com'.

So when I get to subdomain1.example.com. i run differend code in view than excample.com - simple middleware for that like here: Django caching for subdomains

The thing is going wrong when I refresh simultonously pages form different domains (eg. using different tab browser). The result produce output of last refreshed page. And such behaviour do not depend on IP (if someone else is going onto some other subdomain in the same time you are entering main page you will get that subdomain content).

If I wait for loading page first then i move to other everythins is loaded correctly :|

If I turn off caching the problem does not exists.

My soft spec:

  • Ubuntu 8.04 LTS
  • Apache + mod-wsgi
    • threads 10 processes not defined multiprocess=false
  • Django 1.23
  • file caching backend

MIDDLEWARE:

class Subdomains:
    def process_request(self, request):
        u'''
            przekierowuje na stronę główną, jeżeli subdomena z której weszliśmy nie jest subdomeną miasta znajdującego się w bazie. Oraz ustawia zmienną request.META['city']!
        '''
        city = get_city_from_host(request.get_host())
        request.city=None
        if city:
            try:
                city = City.objects.filter(slug__exact=city)
                request.city=city[0].slug
            except:
                return HttpResponsePermanentRedirect(ROOT_URL)   

VIEW:

def post_data(request,address,id):
    url_root = settings.ROOT_URL
    city_subdomain = request.city
    if city_subdomain:
        random_posts = Post.objects.filter(city__slug=city_subdomain).order_by('?')
        if random_posts.count() <= 10:
            pass
        else:
            random_posts = random_posts[:10]

        city = City.objects.filter(slug__exact =  city_subdomain)[0]
        try:
            post = Post.objects.get(id = int(id), city__slug__exact=city.slug)
            nearestinposts = post.nearestinpost_set.select_related(depth=2).all()
            return render_to_response('post_data.html', locals())
        except:
            return HttpResponsePermanentRedirect('http://%s.%s/' % (city_subdomain, settings.ROOT_URL))

    return HttpResponsePermanentRedirect('http://%s' % settings.ROOT_URL)

SETTINGS.PY

CACHE_BACKEND = 'file://%s/cache/' % PROJECT_DIR
CACHE_MIDDLEWARE_SECONDS = 6000
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'middleware.default.Subdomains',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
)

To modify CACHE_KEY i use hack: Django caching for subdomains

Community
  • 1
  • 1
lechup
  • 3,031
  • 27
  • 26
  • You'll need to show the code for the view and how you're caching it. – Daniel Roseman Oct 20 '10 at 07:53
  • I guess you are using a single cache for all sub-domains. In this case, add the sub-domain as a prefix to the cache-key. Otherwise different sub-domains will overwrite each other's cached items. – OmerGertel Oct 20 '10 at 12:04
  • @OmerGertel: I used different ways of changing CACHE_KEY - ended with http://stackoverflow.com/questions/772050/django-caching-for-subdomains/1364942#1364942 . And I've run this issue at the beginning :) Now when I do not make simultanous request everything is OK - i'm getting different content. I'm wondering if Apache / mod_wsgi is not configured somehow to interfere with django cache - I have to check headers. – lechup Oct 20 '10 at 13:41
  • @Daniel I've just added some code :) – lechup Oct 20 '10 at 14:00
  • Oh and I almost forgot - on my DEVELOPMENT server everything is OK :| I can push refresh as many time I want in more than one tab - maybe it is Threads / Processess issue? I guess DEV server is one process and thread? – lechup Oct 20 '10 at 14:05
  • Are you using Google analytics? http://www.codekoala.com/blog/2010/site-wide-caching-django/ Also, maybe the subdomains middleware should be first, if it changes the request. – OmerGertel Oct 20 '10 at 17:04
  • I'll give it a shot! Regarding position of middleware - it should be before FetchFromCacheMiddleware - cause it works on Request. UpdateCacheMoiddleware works on Response so I guess it doesn't matter at all? Or I'm missing something? :) – lechup Oct 24 '10 at 09:49

2 Answers2

1

After some consideration and reading some documentation about caching I moved to simpler solution which doesn't require modifing django:

  • add middleware Subdomain as provided below
class Subdomains:
    def process_request(self, request):
        request.META['HTTP_X_SUBDOMAIN'] = request.get_host()


    def process_response(self, request, response):
        response['X-Subdomain'] = request.META['HTTP_X_SUBDOMAIN']
        return response
  • add middleware to Your middleware classes in settings.py (watch out for django.contrib.messages.middleware.MessageMiddleware and django.contrib.auth.middleware.AuthenticationMiddleware + session wide caching issue)
MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.gzip.GZipMiddleware',
    'middleware.default.Subdomains',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware', # we need that to make auth middleware not to add Vary: Cookie to each response
    'django.middleware.cache.FetchFromCacheMiddleware',
)
  • in views use

from django.views.decorators.vary import vary_on_headers

@vary_on_headers('X-Subdomain')

lechup
  • 3,031
  • 27
  • 26
0

I finally found solution to my problem! The issue was that I had two version of django installed (egg + setup.py). As a result I changed not right utils/cache.py _i18n_cache_key_suffix() function (i'm adding host to cache_key).

def _i18n_cache_key_suffix(request, cache_key):
    """If enabled, returns the cache key ending with a locale."""
    if settings.USE_I18N:
        # first check if LocaleMiddleware or another middleware added
        # LANGUAGE_CODE to request, then fall back to the active language
        # which in turn can also fall back to settings.LANGUAGE_CODE
        cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language())
    cache_key += '.%s' % (request.get_host())
    return cache_key

So what should You do if you want subdomain caching?

  • if you are using something changing Your cookies on each request (eg. Google Analytics), enable StripCookies middleware:

    class StripCookies(object):
    STRIP_RE = re.compile(r'\b(_[^=]+=.+?(?:; |$))')

    def process_request(self, request):
        cookie = self.STRIP_RE.sub('', request.META.get('HTTP_COOKIE', ''))
        request.META['HTTP_COOKIE'] = cookie
    
  • modify /path/to/django/utils/cache.py and there _i18n_cache_key_suffix() function mentioned in this post

Zulu
  • 8,765
  • 9
  • 49
  • 56
lechup
  • 3,031
  • 27
  • 26