appengine ja-night-sapporo#1 bt

14
appengine ja night sapporo#1 AppEngineLowerな世界 shin1ogawa@株式会社トップゲート

Upload: shinichi-ogawa

Post on 24-Jan-2015

881 views

Category:

Documents


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Appengine ja-night-sapporo#1 bt

appengine ja night

sapporo#1AppEngineのLowerな世界

shin1ogawa@株式会社トップゲート

Page 2: Appengine ja-night-sapporo#1 bt

各サービスの実行(RPC)の仕組みApiProxy#getDelegate()

ApplicationHighLevelAPI

LowLevelAPI

ApiProxy#getDelegate()

サービスのStub

PB

PB

Page 3: Appengine ja-night-sapporo#1 bt

Delegate#makeSyncCall()Service名,Method名,Request(byte[])

ApiProxy#getDelegate()#makeSyncCall()

PB(byte[]) サービスのStub

Page 4: Appengine ja-night-sapporo#1 bt

Delegateを自分で実装する

•デフォルトの実装(ApiProxyLocalImpl)を使用しなければサービスのスタブを使用できないのでこれを継承するかこれへ処理を委譲する。•継承すると…ローカル/デプロイ環境に依存してしまうので内部でApiProxy#getDelegate()を取得し、それへ委譲する•各サービスへのアクセスをフックする事が可能になる。AOPっぽいカンジ。

Page 5: Appengine ja-night-sapporo#1 bt

例0: 全てのRPCを記録する

final ApiProxy.Delegate defaultDelegate = ApiProxy.getDelegate();

public byte[] makeSyncCall( Environment environment, String service, String method, byte[] request) throws ApiProxyException { System.out.println(service + “#” + method); defaultDelegate.makeSyncCall( serviceName, methodName, request);}

Page 6: Appengine ja-night-sapporo#1 bt

例1: メンテナンス状態を作る

•DatastoreへのPutやDeleteが行われた時に、強制的に CapabilityDisabledException を投げるDelegateを作る。•テスト時に「データストアがメンテナンス中だった場合の振る舞い」を確認することができる。

Page 7: Appengine ja-night-sapporo#1 bt

ReadOnlyDelegatepublic byte[] makeSyncCall( Environment environment, String service, String method, byte[] request) throws ApiProxyException { if (service.equals(“datastore_v3”) && method.equalsIgnoreCase(“Put”) ) { throw new CapabilityDisabledException(); } defaultDelegate.makeSyncCall( serviceName, methodName, request);}

Page 8: Appengine ja-night-sapporo#1 bt

例2:ある日重要な事実に気づいたねっとりとServer側を監視してたら…

•デプロイ環境でApiProxy.setDelegate(覗き見Delegate)して、実際のサービスとやりとりされるProtocolBufferオブジェクトを観察。•よくよく観察してみると、ローカル環境と同じProtocolBufferオブジェクトが使用されている。

Page 9: Appengine ja-night-sapporo#1 bt

何か思いついちゃった!つまり

•ローカル環境でOreOreDelegateを実装し、#makeSyncCall()をフックして、Stubにリクエストを渡さずそのままデプロイ環境へ転送する。•デプロイ環境は受け取った値を使用してApiProxy.getDelegate().makeSyncCall()を実行し、結果をローカル環境へ返す。•ローカル側のOreOreDelegateはその結果を何食わぬ顔でLow-Level APIへ返す• Low-Level APIを経由してApplicationまで返る

Page 10: Appengine ja-night-sapporo#1 bt

ProtocolBuffer on HTTP左がローカル環境、右がデプロイ環境

OreOreDelegate

サービス本体

OreOreServlet

PB

PB

Application

LowLevelAPI

PB

Page 11: Appengine ja-night-sapporo#1 bt

MakeSyncCallServletサーバ側でmakeSyncCall()するだけ

String service = req.getHeader(SERVICE_NAME);String method = req.getHeader(METHOD_NAME);byte[] requestBytes = IOUtils.toByteArray(req.getInputStream());byte[] responseBytes = ApiProxy.getDelegate().makeSyncCall( ApiProxy.getCurrentEnvironment(), service, method, requestBytes);resp.getOutputStream().write(responseBytes);

Page 12: Appengine ja-night-sapporo#1 bt

MakeSyncCallDelegateMakeSyncCallにつなぐだけpublic byte[] makeSyncCall( Environment environment, String service, String method, byte[] request) throws ApiProxyException { return protocolBufferOnHttp( environment, service, method, request);}

byte[] protocolBufferOnHttp(.....) { // makeSyncCallServletにPostして // byte[]を受け取り、それを返すだけ。}

Page 13: Appengine ja-night-sapporo#1 bt

あっさり動いたこの仕組みを使うと

•ローカル環境でDatastoreにクエリ→なぜかデプロイ環境のDatastoreの結果が返る

•ローカル環境でDatastoreに保存→なぜかデプロイ環境のDatastoreに保存される

•ローカル環境でMemcacheをクリア→なぜかデプロイ環境のMemcacheが空っぽ

Page 14: Appengine ja-night-sapporo#1 bt

ご清聴ありがとうございました!

shin1ogawa@株式会社トップゲート