Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django-compressor / django-storages links being wrongly cached; expiring

I have a Heroku setup with django-compressor compressing my CSS and JS files. My default cache backend is set up with memcached (actually Memcachier when on Heroku). My static files are being served on an Amazon S3 instance (handled by django-storages and boto). Generally my setup is in line with this one from the django-compressor docs.

In my pages, the links to my compressed files have an "expires" query that seems to be an hour from when the link is generated. I don't want to set there to be no expiration for all CSS or JS requests because I have some CSS and JS that I don't compress (it gives me errors when I try... probably a different question).

However, once an hour the links break and the site has no more styles or JS. It looks like the link, or at least the expires header, is being cached and not regenerated, so after the time in the expires argument passes, Amazon no longer returns the file. If I flush the memcache, it changes the expires header in the link to an hour from then, which fixes the problem for an hour, until it expires again.

Here is an example of a link that was generated around 1:39 PM EST today, Tuesday, September 18: https://zen180-static.s3.amazonaws.com/CACHE/css/68d31794a646.css?Signature=u%2FTxeF7LBBZTDV79YovOjoK2tcw%3D&Expires=1347993542&AWSAccessKeyId=AKIAIJ7VKLEX7HIMJZCA. After it is first generated, the page continues to serve that link without alteration. Around 2:39 EST (i.e. the Unix time 1347993542, from the expires argument in the URL), that link stopped working and sent back an "Expired" XML message (the same one it does now). But the bad link was still there on my page until I flushed memcache.

Here are the relevant settings:

COMPRESS_ENABLED = True

STATICFILES_STORAGE = '[my app's name].storage.CachedS3BotoStorage' (a subclass of S3BotoStorage that is almost identical to the one from django-compressor's docs linked above)

COMPRESS_STORAGE = STATICFILES_STORAGE

COMPRESS_URL = STATIC_URL

CACHES = {
  'default': {
    'BACKEND': 'django_pylibmc.memcached.PyLibMCCache',
    'LOCATION': 'localhost:11211',
    'TIMEOUT': 500,
    'BINARY': True,
  }
}

Here is the error:

<Error>
<Code>AccessDenied</Code>
<Message>Request has expired</Message>
<RequestId>81A63F24378ECB5E</RequestId>
<Expires>2012-09-18T18:39:02Z</Expires>
<HostId>lIr5l9Fna95DUfk6hUsWqhO5EQNn6Ayu8BatpEavis8YzLvsaJRru4O8P/50pgMy</HostId>
<ServerTime>2012-09-18T18:59:51Z</ServerTime>
</Error>
like image 568
Daniel Robinson Avatar asked Sep 18 '12 19:09

Daniel Robinson


People also ask

What is compressor in Django?

Compresses linked and inline JavaScript or CSS into single cached files. Django Compressor processes, combines and minifies linked and inline Javascript or CSS in a Django template into cacheable static files. It supports compilers such as coffeescript, LESS and SASS and is extensible by custom processing steps.

How do I concatenate and compress data in Django?

For increased performance, the concatenation and compressing process can also be run once manually outside of the request/response cycle by using the Django management command manage.py compress. Django Compressor is highly configurable and extensible.

How do I install Django-storages from PyPI?

django-storages is a collection of custom storage backends for Django. Use pip to install from PyPI: Each storage backend has its own unique settings you will need to add to your settings.py file. Read the documentation for your storage engine (s) of choice to determine what you need to add.

What is the best way to parse HTML in Django?

Django Compressor is highly configurable and extensible. The HTML parsing is done using lxml or if it’s not available Python’s built-in HTMLParser by default. As an alternative Django Compressor provides a BeautifulSoup and a html5lib based parser, as well as an abstract base class that makes it easy to write a custom parser.


1 Answers

If you want the browser to cache your static content, set the settings.AWS_HEADERS accordingly (as outlined in Amazon's best practices):

AWS_HEADERS = {
    'Expires': 'Sun, 19 Jul 2020 18:06:32 GMT'
}

If you really need the link to be regenerated, find the place it is stored in memcache and set the same cache time you send as link expiration time to Amazon (judging from django-compressor docs it should be one of settings.COMPRESS_*_DELAY).

like image 184
patrys Avatar answered Sep 18 '22 01:09

patrys