GAE Python で Task Queue

クラウドしたいということで、Google App Engine で遊びはじめた。
まず、たくさんのデータを登録するために、PythonでTask Queue APIを使ってみた。

例の動作内容

  • OPMLを取得する
  • OPMLXMLをperseしてmemcacheに入れる。
  • 200件ごとに分割してTask Queueに登録する。

Task Queueに登録すると勝手に、CPUに割り当てて並列実行してくれる。無料版の場合、最大5個まで同時実行してくれる。並列に実行しているのを見ると楽しい。

DataStoreへの登録は1-10件/1秒らしく、200件で24秒かかる。分割を250件にすると30秒を超えてTaskが途中でkillされる。

DataStoreに5000件登録するだけで、無料版のCPU時間の2%を使ってしまう。ということは、無料版だと25万件登録するとCPU時間のQuota/1dayに引っ掛かるっぽい。

登録するだけなら簡単。だけど、DataStoreをどう使うかが悩ましい。

参考;

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.api import urlfetch
from google.appengine.api import memcache
from google.appengine.api.labs import taskqueue
from xml.etree.ElementTree import fromstring

import datetime

Config = { 
         'User' : 'eggman_',
         'split' : 200,
         }

class Topmls(db.Model):
    created                  = db.DateTimeProperty(auto_now_add=True)
    user					 = db.StringProperty()
    url                      = db.StringProperty()
    title                    = db.StringProperty()

def get_opml(url):
  outlines = memcache.get(url)
  if outlines is None:
    result = urlfetch.fetch(url, '', urlfetch.GET, headers={'User-Agent': 'http://twitter.com/eggman'})
    elem = fromstring(result.content)
    outlines = list(reversed(elem.findall('./////outline')))
    memcache.add(url ,outlines, 3600)
  return outlines

class MainHandler(webapp.RequestHandler):
  def get(self):

    user = Config['User']
#    url = 'http://reader.livedoor.com/user/' + user + '/opml'
    url = 'http://nolist.jp/opml'
    
    outlines = get_opml(url)
    for i in range(0, len(outlines), Config['split']):
      taskqueue.add(url='/insert_opml_worker', params={'url': url,
                                                       'user' : user,
                                                       'start' : i,
                                                      })

class InsertOpmlWorker(webapp.RequestHandler):
  def post(self):
    user = self.request.get('user')
    url  = self.request.get('url')
    start = int( self.request.get('start') )
    
    outlines = get_opml(url)

    for o in outlines[start:start+Config['split']]:  
      p = Topmls(  title   = o.get('title'),
                   url     = o.get('htmlUrl'),
                   user    = user,
               )
      p.put()

def main():
  application = webapp.WSGIApplication([('/check', MainHandler),
                                        ('/insert_opml_worker', InsertOpmlWorker)],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
  main()