Google App EngineでFizzBuzz
Google App Engine(以下GAE)って無料で使えるわりにいろんな便利な機能があります。今回はそのGAEの便利機能を使ってFizzBuzzを作ってみた。
まずはGoogleアカウント。最近はどこのサイトでもログインが必要。でも認証機能って一から作ると面倒だよね。そこでGAEではGoogle純正の認証機能が用意されてる。超便利。
http://code.google.com/intl/ja/appengine/docs/python/users/
次はMemcache。GAEでデータを保存するためにはいちいちModelを定義しなくちゃいけない。永続的に保存しとくにはそれしかないけど、ちょっとだけ覚えておきたいデータとかもあるよね。そんなときに便利なのがMemcache。なによりModel書かなくてもいいのが簡単(複雑なデータは保存出来ないけど)。
http://code.google.com/intl/ja/appengine/docs/python/memcache/
3番目はTaskqueue。GAEでもっとも頭を悩ませるのが30秒ルール。時間がかかる処理が出来ないってこと。そこでTaskqueueの出番となる。大きな処理は分割してキューで非同期に処理するってわけ。
http://code.google.com/intl/ja/appengine/docs/python/taskqueue/
最後はメール。GAEだと超簡単にメール出せます。
http://code.google.com/intl/ja/appengine/docs/python/mail/
これら4つの機能を組み合わせて作ったのが以下のFizzBuzz。まずGoogleアカウントでログインします。するとMemcacheでFizzBuzzの答えを保存する場所が確保されて、最初の数字1のFizzBuzzの答えを求めるためのリクエストをTaskqueueに追加します。Taskqueueから呼ばれたリクエストは、パラメータの数字のFizzBuzzを求めてMemcacheに保存。そして、インクリメントした数字と共にまたリクエストをTaskqueueに追加します。ドミノみたいな感じです。最後に100までFizzBuzzが求められたら、ログインしたときのGoogleアカウントのメールアドレスに答えを送信します。まさにGAEによるピタゴラスイッチ。これ、意外と早くメールが届くのでびっくりしました。
http://gist.github.com/307608
# -*- coding: utf8 -*- from google.appengine.ext import webapp from google.appengine.ext.webapp.util import run_wsgi_app from google.appengine.api import memcache from google.appengine.api import mail from google.appengine.api.labs import taskqueue from google.appengine.api import users class FizzBuzzHandler(webapp.RequestHandler): def post(self): mailaddress = self.request.get('mailaddress') num = self.request.get('number') if not mailaddress or not num: return key = 'fizzbuzz' + mailaddress num = int(num) result = memcache.get(key) if result is None: return result += self.fizzbuzz(num) + '\n' if num < 100: memcache.set(key, result, 3600) taskqueue.add(url='/fizzbuzz2', params={'mailaddress': mailaddress, 'number': str(num+1)}) else: mail.send_mail('hoge@foo.com', mailaddress, 'FizzBuzz Result', result) def fizzbuzz(self, num): if num % 3 == 0: if num % 5 == 0: return 'FizzBuzz' else: return 'Fizz' elif num % 5 == 0: return 'Buzz' else: return str(num) class MainHandler(webapp.RequestHandler): def get(self): w = self.response.out.write w('<html><body>') user = users.get_current_user() if user: memcache.set('fizzbuzz'+user.email(), '', 3600) taskqueue.add(url='/fizzbuzz2', params={'mailaddress': user.email(), 'number': '1'}) w(('処理が完了したら %s にメールを送ります' % user.email())) w(('<br /><a href="%s">ログアウト</a>' % users.create_logout_url('/fizzbuzz'))) else: w((u'<a href="%s">ログインするとFizzBuzz開始</a>' % users.create_login_url('/fizzbuzz'))) w('</body></html>') application = webapp.WSGIApplication( [('/fizzbuzz2', FizzBuzzHandler), ('/fizzbuzz', MainHandler)], debug=True) def main(): run_wsgi_app(application) if __name__ == '__main__': main()