Upload
satoshi-tagomori
View
2.133
Download
0
Embed Size (px)
DESCRIPTION
Citation preview
AppEngine 1.4.0 SDKソースコードから見る実行環境
bpstudy #40 (2010.12.21)@tagomoris
tagomorisTAGOMORI Satoshi / 田籠 聡
Twitter: @tagomorisE-mail: [email protected]
Blog: http://d.hatena.ne.jp/tagomoris/
GAETestBase (python), simpleoauth-gae (python),
Stratum(ruby), PassengerMonitor(ruby), ... GlassDolphinsource code viewer for iPad/iPhone
本日の話AppEngine Python SDKのコードの話とか
空白とか
AppEngine 実行環境の構造とか
remote_api の話とか
ツッコミは適宜どうぞ
SDK読む?
ドキュメント読む?
AppEngineのコードの特徴• Python, Javaで実装がかなり似ている
• 内部APIのコール名まで共通点が多い
• 基本的にバックエンドへのRPCが透けて見える
• Service側は全部共通だし
• 各サービスの制約や最適化方法も多分共通でしょう
• MultiQueryとかー、batch putとかー
GoogleのPythonコード• 基本的にすごく綺麗で読みやすい
• メソッド名から内容がちゃんと分かるのはスゴい
• ただし処理がすごく細切れ
• 数行ですぐ他所に処理が飛ぶ
• 同じ名前のメソッドがあちこちのモジュールにある
• Google Python Style Guide
• http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
• http://works.surgo.jp/translation/pyguide.html (和訳 rev 2.15)
Google流モジュール取扱い• import方法
import google.appengine.ext.db.*
Model.get(...)
from google.appengine.ext import db
db.Model.get(...)
Google流モジュール取扱い•関数定義の再代入の多用
# google/appengine/api/datastore.py
def IsInTransaction():
....
_CurrentTransactionKey = IsInTransaction
# google/appengine/ext/db/__init__.py
run_in_transaction = datastore.RunInTransaction
RunInTransaction = run_in_transaction
空白
一番楽しいのは「空白の行」
google/appengine/api/appinfo.py (...260, ...636)google/appengine/api/datastore_types.py(1129, ...1584)
google/appengine/cron/GrocLexer.py, GrocParser.pygoogle/appengine/datastore/datastore_sqlite_stub.py (...88)
google/appengie/ext/db/__init__.py (...1569)google/appengine/runtime/apiproxy.py (...85)
そのほかあちこち
合言葉は
MakeSyncCall
from google.appengine.ext import webappfrom google.appengine.ext.webapp.util import run_wsgi_appfrom google.appengine.ext import db
class Tekitou(db.Model): pass
class MainPage(webapp.RequestHandler): def get(self): Tekitou.get_by_id(100) self.response.out.write("<html><body><p>tagomoris test page...</p></body></html>")
application = webapp.WSGIApplication([('/', MainPage), #('/msc_datastore', DatastoreMakeSyncCall), ], debug=True)
def main(): run_wsgi_app(application)
if __name__ == '__main__': main()
適当に書いたハンドラ
Traceback (most recent call last): File ".../google/appengine/ext/webapp/__init__.py", line 515, in __call__ handler.get(*groups) File "/Users/tagomoris/Documents/tagomoris-test/main.py", line 14, in get Tekitou.get_by_id(100) File ".../google/appengine/ext/db/__init__.py", line 1115, in get_by_id return get(keys[0], config=config) File ".../google/appengine/ext/db/__init__.py", line 1320, in get entities = datastore.Get(keys, config=config) File ".../google/appengine/api/datastore.py", line 443, in Get return _GetConnection().async_get(config, keys, extra_hook).get_result() File ".../google/appengine/datastore/datastore_rpc.py", line 548, in get_result self.check_success() File ".../google/appengine/datastore/datastore_rpc.py", line 519, in check_success rpc.check_success() File ".../google/appengine/api/apiproxy_stub_map.py", line 501, in check_success self.__rpc.CheckSuccess() File ".../google/appengine/api/apiproxy_rpc.py", line 149, in _WaitImpl self.request, self.response) File ".../google/appengine/api/datastore_file_stub.py", line 618, in MakeSyncCall response) File ".../google/appengine/api/apiproxy_stub.py", line 80, in MakeSyncCall raise RuntimeError, "just before call method %s" % ('_Dynamic_' + call)
RPC実行直前で例外を投げた状態
MakeSyncCallの壁 ApiProxyStubMap
Taskqueue
Memcache
Users
ApiProxyStub
UrlFetch
ext.db
ユーザアプリケーションのコード
ApiProxyStubMap
Datastore
ServiceStubDatastoreFileStub DatastoreSqliteStub CapabilityStub
ProtocolBuffer
各種RPC
MakeSyncCallの壁 ApiProxyStubMap
Taskqueue
Memcache
Users
ApiProxyStub
UrlFetch
ext.db
ユーザアプリケーションのコード
ApiProxyStubMap
Datastore
ServiceStubDatastoreFileStub DatastoreSqliteStub CapabilityStub
ProtocolBuffer
各種RPC
このへん読みたい
大事なこと ふたつ
•どこを読むべきかを意識しながら
•次の行き先を確認しながら
では読んでみよう!
1.google/appengine/ext/db/__init__.py (1115, get_by_id)2.google/appengine/ext/db/__init__.py (1320, get)3.google/appengine/api/datastore.py (443, Get)4.google/appengine/datastore/datastore_rpc.py (548, get_result)5.google/appengine/datastore/datastore_rpc.py (519, check_success)6.google/appengine/api/apiproxy_stub_map.py (501, check_success)7.google/appengine/api/apiproxy_rpc.py (149, _WaitImpl)8.google/appengine/api/datastore_file_stub.py (618, MakeSyncCall)9.google/appengine/api/apiproxy_stub.py (80, MakeSyncCall)
だいたいこんな順番で潜っていくよー
番外: google/appengine/runtime/apiproxy.py
remote_api• 開発環境のStubを全部 RemoteStub に置き換える
• Datastoreだけ RemoteDatastoreStub
• RemoteStub が全てのRPC(MakeSyncCall)を受け取る
• 処理するフリをしてappspotにそのままHTTP RPCで投げる
• appspotでRemoteApi専用のハンドラが受け取る
• そのまま本物のApiProxyStubに投げて処理させる
remote_apiの用途
• remote_api_shell.py で実験やメンテナンス
• GAETestBase
• URLFetchService 動作確認とか (to Twitter)
remote_apiのRPC構造
remote_api handler
ApiProxyStubMap
user application
ApiProxyStubMap
Service
ServiceStubRemoteStub
remote_api_shell
HTTP RPC
remote_apiのRPC構造
remote_api handler
ApiProxyStubMap
user application
ApiProxyStubMap
Service
ServiceStubRemoteStub
remote_api_shell
MakeSyncCall
MakeSyncCall
HTTP RPC
remote_apiのRPC構造
remote_api handler
ApiProxyStubMap
user application
ApiProxyStubMap
Service
ServiceStubRemoteStub
remote_api_shell
MakeSyncCall
MakeSyncCall
HTTP RPC
何が言いたかったか
AppEngineはSDKのコードを読むといろいろわかる
AppEngineはコードさえ書けばあれこれできる
コードを書かないと何もできない
わからないことがあったコードを読もう。できないことがあったらコードを書いて解決しよう。
問題と解決をみんなでシェアしよう。あなたの問題は、きっとみんなの問題だ。
ありがとうございました