Engineer in Tokyo

Google Appengine SDK 1.2.3

The Google Appengine SDK 1.2.3 was just released and contains some often asked for goodies such as Django 1.0 support and support for a task queue API.

I haven’t found much information about the Django 1.0 version in Appengine but here are some links with some related information about the Task Queue API.

The code looks something like the code below. You tell the task queue that you have some work to do later and which url the worker is located at. The worker is then called via a Web Hook post request with the parameters you gave it. The request is limited to 30 seconds like most requests. It will continue retry the work until it gets a 200 OK response (That isn’t to say that you should just return a 500 HTTP status if your worker cannot complete in time. If you have more work your worker should add itself back to the queue and return 200 OK).

Tasks are executed as soon as possible and only if there is work so it’s quite a bit different from the cron support which runs every so often regardless of whether there is work or not. Based on the demo from Google I/O it runs faster than normal requests so you might even have some work finished before the request that added the work to the task queue finishes and gets back to your browser!

import wsgiref.handlers
from google.appengine.api.labs import taskqueue
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template

class Counter(db.Model):
  count = db.IntegerProperty(indexed=False)

class CounterHandler(webapp.RequestHandler):
  def get(self):
    self.response.out.write(template.render('counters.html',
                                            {'counters': Counter.all()}))

  def post(self):
    key = self.request.get('key')

    # Add the task to the default queue.
    taskqueue.add(url='/worker', params={'key': key})

    self.redirect('/')

class CounterWorker(webapp.RequestHandler):
  def post(self):
    key = self.request.get('key')
    def txn():
      counter = Counter.get_by_key_name(key)
      if counter is None:
        counter = Counter(key_name=key, count=1)
      else:
        counter.count += 1
      counter.put()
    db.run_in_transaction(txn)

def main():
  wsgiref.handlers.CGIHandler().run(webapp.WSGIApplication([
    ('/', CounterHandler),
    ('/worker', CounterWorker),
  ]))

if __name__ == '__main__':
  main()