2016-08-06 4 views
3

プロダクショントラフィックのパーセンテージについては、を別のバージョンのアプリケーションに複写します。これは非同期的に発生する必要があるので、クライアントにサービス時間を倍増させることはありません。webapp2.RequestHandlerリクエストを別のURLに非同期で複製できますか?

これは、prodバージョンとproduction候補バージョンで生成された応答を比較できるようにするためです。彼らの結果が適切に似ているならば、私は新しいバージョンが何かを壊していないと確信することができます。 (私は、アプリケーションへの機能変更を加えた場合、私はこの比較からの応答の必要な部分を除外すると思います。)

だから私はと同等を探しています:

class Foo(webapp2.RequestHandler): 
    def post(self): 
    handle = make_async_call_to('http://other_service_endpoint.com/', self.request) 

    # process the user's request in the usual way 

    test_response = handle.get_response() 

    # compare the locally-prepared response and the remote one, and log 
    # the diffs 

    # return the locally-prepared response to the caller 

UPDATE google.appengine.api.urlfetchは私の問題への潜在的な解決策として提案されたが、それは私が生産(要求がされるまで外出しないで欲しかったように動作けれども、それは、dev_appserverに同期ですget_response()が呼び出され、ブロックされます)。 :

start_time = time.time() 
    rpcs = [] 

    print 'creating rpcs:' 
    for _ in xrange(3): 
     rpcs.append(urlfetch.create_rpc()) 
     print time.time() - start_time 

    print 'making fetch calls:' 
    for rpc in rpcs: 
     urlfetch.make_fetch_call(rpc, 'http://httpbin.org/delay/3') 
     print time.time() - start_time 

    print 'getting results:' 
    for rpc in rpcs: 
     rpc.get_result() 
     print time.time() - start_time 


creating rpcs: 
9.51290130615e-05 
0.000154972076416 
0.000189065933228 
making fetch calls: 
0.00029993057251 
0.000356912612915 
0.000473976135254 
getting results: 
3.15417003632 
6.31326603889 
9.46627306938 

アップデート2は

ので、いくつかの他のオプションと一緒に遊んでた後、私は完全に非ブロック要求にする方法が見つかりました:

start_time = time.time() 
rpcs = [] 

logging.info('creating rpcs:') 
for i in xrange(10): 
    rpc = urlfetch.create_rpc(deadline=30.0) 
    url = 'http://httpbin.org/delay/{}'.format(i) 
    urlfetch.make_fetch_call(rpc, url) 
    rpc.callback = create_callback(rpc, url) 
    rpcs.append(rpc) 
    logging.info(time.time() - start_time) 

logging.info('getting results:') 
while rpcs: 
    rpc = apiproxy_stub_map.UserRPC.wait_any(rpcs) 
    rpcs.remove(rpc) 
    logging.info(time.time() - start_time) 

を...しかし、注目すべき重要な点は、は、dev_appserverでurllibの非同期フェッチオプションが機能していないことです。これを発見したので、@ DanCornilescuのソリューションを試してみると、それは本番環境では正しく動作するが、dev_appserverでは正しく動作しないことがわかりました。

答えて

1

URLフェッチサービスは、非同期要求をサポートしています。からIssuing an asynchronous request

HTTP(S)要求はデフォルトで同期します。非同期 要求を発行するには、あなたのアプリケーションが必要があります。

  1. urlfetch.create_rpc()を使用して、新しいRPCオブジェクトを作成します。このオブジェクトは、後続のメソッド呼び出しでの非同期呼び出しを表します。
  2. urlfetch.make_fetch_call()を呼び出してリクエストしてください。このメソッドは、RPCオブジェクトと要求ターゲットのURLをパラメータとして受け取ります。
  3. RPCオブジェクトのget_result()メソッドを呼び出します。このメソッドは、要求が成功した場合は結果オブジェクトを返し、要求中にエラーが発生した場合は例外を発生します( )。

次のスニペットは、Pythonアプリケーションからの基本的な非同期の要求を行う方法を示しています。まず、App EngineのSDKからのURLfetchライブラリ をインポート:

from google.appengine.api import urlfetch 

次は、非同期要求を行うためにUrlFetchの使用:

rpc = urlfetch.create_rpc() 
urlfetch.make_fetch_call(rpc, "http://www.google.com/") 

# ... do other things ... 
try: 
    result = rpc.get_result() 
    if result.status_code == 200: 
     text = result.content 
     self.response.write(text) 
    else: 
     self.response.status_code = result.status_code 
     logging.error("Error making RPC request") 
except urlfetch.DownloadError: 
    logging.error("Error fetching URL0") 

注:で言及Sniggerfardimungusの実験を1として質問の更新非同期呼び出しは、開発サーバーでは期待通りに機能しない可能性があります(同時実行ではなく、直列化されていますが、GAEに展開すると非同期呼び出しが行われます)。個人的に私はまだ非同期呼び出しを使用していないので、私は本当に言うことができません。

ブロックが意図されていない場合は、にすべてを返信します。元のリクエストのコピーと生産準備の応答をタスクキューにプッシュしてから元のリクエストに応答できますneglijible delay(タスクのエンキュー)。

それぞれのタスクキューのハンドラは、元のリクエストのクリティカルパスの外側で、元のリクエストのコピーを使用してステージングアプリにリクエストします(非同期でもなくても、生産アプリの応答時間に影響を与える)、応答を得て、生産準備応答と比較したり、デルタなどを記録したりすることができます。これは、プロダクションアプリへの変更を最小限に抑え、必要に応じて展開/ 。

+0

get_result()は同期です。上記の編集を参照してください。 – Sniggerfardimungus

+0

はい、しかし、あなたはあなたの "#通常の方法でユーザーの要求を処理する"ことに対応する_after_ '' ... do do other things ... 'を実行します。 .get_response() "を元のリクエストに返信する前 –

+0

私はクライアントにサービス時間を倍増させないという質問からの要求は、質問の重要な部分です。 – Sniggerfardimungus

関連する問題