View
881
Download
0
Category
Preview:
DESCRIPTION
Citation preview
appengine ja night
sapporo#1AppEngineのLowerな世界
shin1ogawa@株式会社トップゲート
各サービスの実行(RPC)の仕組みApiProxy#getDelegate()
ApplicationHighLevelAPI
LowLevelAPI
ApiProxy#getDelegate()
サービスのStub
PB
PB
Delegate#makeSyncCall()Service名,Method名,Request(byte[])
ApiProxy#getDelegate()#makeSyncCall()
PB(byte[]) サービスのStub
Delegateを自分で実装する
•デフォルトの実装(ApiProxyLocalImpl)を使用しなければサービスのスタブを使用できないのでこれを継承するかこれへ処理を委譲する。•継承すると…ローカル/デプロイ環境に依存してしまうので内部でApiProxy#getDelegate()を取得し、それへ委譲する•各サービスへのアクセスをフックする事が可能になる。AOPっぽいカンジ。
例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);}
例1: メンテナンス状態を作る
•DatastoreへのPutやDeleteが行われた時に、強制的に CapabilityDisabledException を投げるDelegateを作る。•テスト時に「データストアがメンテナンス中だった場合の振る舞い」を確認することができる。
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);}
例2:ある日重要な事実に気づいたねっとりとServer側を監視してたら…
•デプロイ環境でApiProxy.setDelegate(覗き見Delegate)して、実際のサービスとやりとりされるProtocolBufferオブジェクトを観察。•よくよく観察してみると、ローカル環境と同じProtocolBufferオブジェクトが使用されている。
何か思いついちゃった!つまり
•ローカル環境でOreOreDelegateを実装し、#makeSyncCall()をフックして、Stubにリクエストを渡さずそのままデプロイ環境へ転送する。•デプロイ環境は受け取った値を使用してApiProxy.getDelegate().makeSyncCall()を実行し、結果をローカル環境へ返す。•ローカル側のOreOreDelegateはその結果を何食わぬ顔でLow-Level APIへ返す• Low-Level APIを経由してApplicationまで返る
ProtocolBuffer on HTTP左がローカル環境、右がデプロイ環境
OreOreDelegate
サービス本体
OreOreServlet
PB
PB
Application
LowLevelAPI
PB
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);
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[]を受け取り、それを返すだけ。}
あっさり動いたこの仕組みを使うと
•ローカル環境でDatastoreにクエリ→なぜかデプロイ環境のDatastoreの結果が返る
•ローカル環境でDatastoreに保存→なぜかデプロイ環境のDatastoreに保存される
•ローカル環境でMemcacheをクリア→なぜかデプロイ環境のMemcacheが空っぽ
ご清聴ありがとうございました!
shin1ogawa@株式会社トップゲート
Recommended