views:

123

answers:

2

I have a view in my Django application that automatically creates an image using the PIL, stores it in the Nginx media server, and returns a html template with a img tag pointing to it's url.

This works fine, but I notice an issue. For every 5 times I access this view, in 1 of them the image doesn't render.

I did some investigation and I found something interesting, this is the HTTP response header when the image renders properly:

Accept-Ranges:bytes
Connection:keep-alive
Content-Length:14966
Content-Type:image/jpeg
Date:Wed, 18 Aug 2010 15:36:16 GMT
Last-Modified:Wed, 18 Aug 2010 15:36:16 GMT
Server:nginx/0.5.33

and this is the header when the image doesn't load:

Accept-Ranges:bytes
Connection:keep-alive
Content-Length:0
Content-Type:image/jpeg
Date:Wed, 18 Aug 2010 15:37:47 GMT
Last-Modified:Wed, 18 Aug 2010 15:37:46 GMT
Server:nginx/0.5.33

Notice the Content-Lenth equals to zero. What could have caused this? Any ideas on how could I further debug this problem?

Edit: When the view is called, it calls this "draw" method of the model. This is basically what it does (I removed the bulk of the code for clarity):

def draw(self):
    # Open/Creates a file
    if not self.image:
        (fd, self.image) = tempfile.mkstemp(dir=settings.IMAGE_PATH, suffix=".jpeg")
        fd2 = os.fdopen(fd, "wb")
    else:
        fd2 = open(os.path.join(settings.SITE_ROOT, self.image), "wb")

    # Creates a PIL Image
    im = Image.new(mode, (width, height))

    # Do some drawing
    .....

    # Saves
    im = im.resize((self.get_size_site(self.width),
                    self.get_size_site(self.height)))
    im.save(fd2, "JPEG")
    fd2.close()

Edit2: This is website: http://xxxcnn7979.hospedagemdesites.ws:8000/cartao/99/

if you keep hitting F5 the image on the right will eventually render.

A: 

Looks like Nginx gets incomplete stat() values, at the time it receives the request for the image-file. If a refresh does render the img, it has race-condition written all over it.

Do you use any caching middleware on the Django side or in nginx?

edited: removed questions answered by op.

CharString
I edited the question and included the code that the view calls. Yes, I am closing the fd before leaving the view. The nginx runs on the same server, so I am just executing an open() in the Nginx media files.
Cesar Canassa
That makes the question a lot more interesting. Seems I don't have the reputation to vote it up yet. Regard this comment as a +1 ;-)
CharString
No, I am not using any caching Middleware in Django side but I believe that nginx is running with gzip compression. Check my edit, I deployed the app to a public server!
Cesar Canassa
+2  A: 

We had this problem a while back when writing HTML pages out to disk. The solution for us was to write to a temporary file and then atomically rename the file. You might also want to consider using fsync.

The full source is available here: staticgenerator/_init_.py, but here are the useful bits:

import os
import stat
import tempfile

...

f, tmpname = tempfile.mkstemp(dir=directory)
os.write(f, content)
# See http://docs.python.org/library/os.html#os.fsync
f.flush()
os.fsync(f.fileno())
os.close(f)
# Ensure it is webserver readable
os.chmod(tmpname, stat.S_IREAD | stat.S_IWRITE | stat.S_IWUSR | stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
# Rename is an atomic operation in POSIX
# See: http://docs.python.org/library/os.html#os.rename
os.rename(tmpname, fn)
Erik Karulf
Thanks man! that should do it!
Cesar Canassa