Search code examples
pythongoogle-app-enginegoogle-cloud-datastoreapp-engine-ndbblobstore

put_async, wait, and callbacks, how to speed up page redirect after an asynchronous file upload


So I have a BlobstoreUploadHandler class that, uses put_async and wait like so:

x = Model.put_async()
    x.wait()

then proceeds to pass some data up front to javascript, so that the user is redirected to the class serving their file upload, it does this like so:

redirecthref = '%s/serve/%s' % (
    self.request.host_url, Model.uploadid)
    self.response.headers['Content-Type'] = 'application/json'
    obj = { 'success' : True, 'redirect': redirecthref }
    self.response.write(json.dumps(obj))

this all works well and good, however, it takes a CRAZY amount of time for this redirect to happen, we're talking minutes, and while the file is uploading, the page is completely frozen. I've noticed I am able to access the link that javascript would redirect to even while the upload is happening and the page is frozen, so my question is, what strategies can I pursue to make the redirect happen right when the url becomes available? Is this what the 'callback' parameter of put_async is for, or is this where I want to look into url_fetch.

Im pretty new to this and any and all help is appreciated. Thanks!

UPDATE:

So I've figured out that the upload is slow for several reasons: I should be using put() rather than put_aync(), which I've found does speed up the upload time, however something is breaking and it's giving me a 500 error that looks like:

POST http://example.com/_ah/upload/AMmfu6au6zY86nSUjPMzMmUqHuxKmdTw1YSvtf04vXFDs-…tpemOdVfHKwEB30OuXov69ZQ9cXY/ALBNUaYAAAAAU-giHjHTXes0sCaJD55FiZxidjdpFTmX/ 500 (Internal Server Error) 

It still uploads both the resources, but the redirect does not work. I believe this is happening on the created upload_url, which is created using

upload_url = blobstore.create_upload_url('/upload')

All that aside, even using put() instead of put_async(), the wait() method is still taking an exorbitant amount of time. If I remove the x.wait(), the upload will still happen, but the redirect gives me:

IndexError: List index out of range

this error is thrown on the following line of my /serve class Handler

qry = Model.query(Model.uploadid == param).fetch(1)[0]

So in short, I believe the fastest way to serve an entity after upload is to take out x.wait() and instead use a try: and except: on the query, so that it keeps trying to serve the page until it doesnt get a listindex error. Like I said, im pretty new to this so actually making this happen is a little over my skill level, thus any thoughts or comments are greatly appreciated, and I am always happy to offer more in the way of code or explanation. Thanks!


Solution

  • Looking back, I wanted to circle up on this since I solved this one shortly after posting about it. What I discovered was that there was no way real way to speed up the upload, other than using put instead of put_async of course.

    But there was a tricky way to access the blob in my redirect url, other than through the Model.uploadid which was not guaranteed to be consistently uploaded by the time the redirect occurred.

    The solution was to simply access the blob using the .keys() method of my upload object and to pass that into the redirect_href, instead of the Model.uploadid

    redirecthref = '%s/serve/%s' % (self.request.host_url, self.get_uploads(‘my_upload_object’)[0].key())
    

    Not sure why the .keys() lookup seemed to bypass the whole upload process, but this seemed to work for me.

    Thanks,