Google Appengine 1.4.0 がリリースされました!! このリリースはかなりでかい!! チャンネルAPI, “Always On” (リザーブインスタンス)、タスクキューの正式リリース、スタートアップリクエスト、バックグラウンド処理の改善などなど、
チャンネルAPI
まずは、一番重要なチャンネルAPI。チャンネルAPIでクライアントブラウザーにプッシュすることができるようになります。内部的には、Google Talk の XMPP インフラを使っているらしくて、それでスケールアウトしてくれます。チャンネルAPI は2つの部分がに分けています。 サーバー再度のチャンネルAPI と チャンネルAPI の Javascript ライブラリ。
チャンネルAPIはサーバー側から、クライアントの通信に使います。クライアントからサーバーへの通信は今までどおりのPOSTがGET HTTPリクエスト。
サーバー側
まずは、チャンネルのIDをクライアントに渡す。クライアントはそのIDを使って、 チャンネルに接続する。
channel.create_channel()
に渡す user
は、ユーザーだけじゃなくて、 内部的に文字列にするので、
create_channel()
に渡すデータは単の文字列でも大丈夫です。
from google.appengine.ext import webapp
from google.appengine.api import channel
from django.template.loader import render_to_string
class MyHandler(BaseHandler):
def get(self):
user = users.get_current_user()
# ユーザーのチャンネルを作る
# create_channel に渡すデータは単の文字列でも大丈夫
id = channel.create_channel(user)
return self.response.out.write(
render_to_string(
"index.html",
{"channel_id": id},
)
)
クライアント側の Javascript はチャンネルに接続
var channel = new goog.appengine.Channel("{{ channel_id }}");
var socket = channel.open();
socket.onopen = function () {
window.setTimeout(function () {
alert("Connected!");
}, 100);
};
// メッセージのハンドラーを登録
socket.onmessage = function (evt) {
// テキストを受けているけど、JSONがおすすめ
// var o = JSON.parse(evt.data);
alert(evt.data);
// do something
};
サーバーからクライアントにメッセージを送る
from google.appengine.api import channel
from google.appengine.api import users
class AjaxHandler(BaseHandler):
def get(self):
user = users.get_current_user()
# メッセージをクライアントに渡す。
# クライアントが接続している状態が不要
# 誰も接続してない場合は何もしない
# ここでテキストデータを送るけど、JSONがおすすめです
channel.send_message(user, "Hello World!!")
Channel API のドキュメント: http://code.google.com/intl/ja/appengine/docs/python/channel/overview.html
Always On
今までは、リクエストが少ない場合は、 Appengine のサーバーインスタンスがすべて落とされるので、 リクエストがその状態で来た時、かなりスピンアップ (サーバーインスタンスの起動)に時間かかってしまいました。 “Always On” という機能を使うと3つのインスタンスを保持してくれます。 有料ですが、 かなりスピンアップに困っている人に好調的だね。
スタートアップリクエスト
この機能もスピンアップにいいのですが、効果がちょっと違うので、説明します。今まで、リクエストが増えて、
スケールアウト(新しいインスタンスの起動)が必要な場合、あるリクエストが新しいインスタンスに割り当てると、
インスタンスがロードに時間かかったり、 DeadlineExceededError
が出たりしました。
スタートアップリクエスト機能は、スケールアウトが必要な場合、ユーザーからのリクエストを割り当てる前に、 スタートアップリクエストをインスタンスに投げる。このリクエストで必要なモジュールを未然にロードできる ようになります。それで、最初のユーザーリクエストが来たら、より速く返せるようになります。
つまり、スタートアップリクエストがスケールアウトする時に効果があるので、 インスタンスがいくらでもあっても効果的です。
使うには、まずはメールみたいに、 inbound_services
を app.yaml
に設定します。
inbound_services:
- warmup
スタートアップリクエストが /_ah/warmup
のURLに来るので、スタートアップリクエストを受けとるURLを app.yaml
に設定する。
- url: /_ah/warmup.*
script: warmup.py
warmup.py
の中に、必要そうなモジュールをインポートする。
# ロードが重いモジュールを未然にロードする
import mybigmodule
import myothermodule
def main():
print "Content-type: text/plain"
print "OK"
タスクキュー正式リリース
今まで、 Appengine のタスクキューは Beta で google.appengine.api.labs.taskqueue
に入っていたけど、 labs から卒業するので、 google.appengine.api.taskqueue
に移動される。 タスクキューのデータもデータのクオータに含まれるようになります。 データクオータにひっかかるので、
ヘビーに使っている人たちはちょっと大変かもしれない。
cron/タスクキューの改善
cron とタスクキューの時間制限は今まで、30秒でしたが、10分になります。 ですが、長く実行しているcronジョブ・タスクは認識され、別インフラに移動されて、 スループット(実行頻度)が落ちるので、速くて小さいタスクが良好だと言われる。
Metadata クエリー
Appengine データストアのメタデータ、Namespace
, Kind
, Property
をクエリすることができるようになりました。 メタデータのモデルクラスは
google.appengine.ext.db.metadata
モジュールに入っています。
Kind
インスタンスが持っている Property
の親になるので、ある Kind
の Property
を取得するには、
ancestor()
クエリができます。
from google.appengine.ext.db.metadata import Namespace, Kind, Property
for namespace in Namespace.all():
print namespace.namespace_name
for kind in Kind.all():
print kind.kind_name
for property in Property.all().ancestor(kind):
print " %s" % property.property_name
ダウンロード
http://code.google.com/intl/en/appengine/downloads.html ではまだ出てないみたいですが、code.google.com のプロジェクトの以下のURLからダウンロードできます。