5

ndbを使用して、@ ndb.toplevelを使用して40個の要素をput_asyncし、ユーザーに出力を書き込んでリクエストを終了したとしますが、それらのput_asyncの1つで競合例外が発生しましたが、応答は500または200になりますか?または、それがタスクである場合、タスクは再実行されますか?

1つの解決策は、リクエストが終了する前に40個のリクエストすべてをget_result()して、それらの例外をキャッチすることです(発生した場合)が、パフォーマンスに影響するかどうかはわかりません。

4

2 に答える 2

4

私が理解している限り、@ ndb.toplevelを使用すると、ハンドラーはすべての非同期操作が終了するのを待ってから終了します。ドキュメントから:

便宜上、リクエストハンドラを@ndb.toplevelで装飾できます。これは、非同期要求が終了するまで終了しないようにハンドラーに指示します。これにより、リクエストを送信し、結果を気にする必要がなくなります。https://developers.google.com/appengine/docs/python/ndb/async#intro

したがって、@ ndb.toplevelを追加することにより、非同期メソッドの実行が終了するまで応答が実際に返されません。@ ndb.toplevelを使用すると、(便宜上)発生したすべての非同期呼び出しでget_resultを呼び出す必要がなくなります。したがって、これに基づいて、非同期クエリが失敗した場合でも、要求は500を返します。これは、すべての非同期クエリが戻る前に完了する必要があるためです。 更新:以下

タスクを使用している場合(私はあなたがタスクキューを意味すると思います)、リクエストが失敗した場合、タスクキューはリクエストを再試行します。したがって、ハンドラーは次のようになります。

def get(self):
    deferred.defer(execute_stuff_in_background, param,param1)
    template.render(...)

そしてexecute_stuff_in_backgroundは、ハンドラーが戻った後、すべての高価なプットを実行します。タスクに競合の問題があった場合でも、元のハンドラーは200を返します。

競合の問題が発生する可能性がある場合は、シャーディングを行うか、フォークジョインキューの実装を使用して書き込みを処理することを検討してください(実装はこちらをご覧ください: http ://www.youtube.com/watch? v = zSDC_TU7rtc#t = 41分35秒

編集:短い答え @ ndb.toplevelは終了する前にすべての結果が終了するのを待つため、非同期リクエストが失敗した場合、リクエストは失敗します(500を返します)。 更新:以下の@alexisの回答を見て、元のテストを再実行しました(データストアの書き込みをオフにし、@ ndb.toplevelで装飾されたハンドラーでput_asyncを呼び出しました)、応答は断続的に500になります(これは実行に依存すると思います)時間)。これと以下の@alexisの回答に基づいて、非同期タスクが例外をスローし、呼び出し元の関数が@ ndb.toplevelで装飾されている場合、結果が500になるとは思わないでください。

于 2012-09-01T10:04:31.670 に答える
3

それは奇妙なことです。私はトップレベルを使用し、反対の動作を期待しています。そしてそれが私が観察していることです。この質問への最初の回答から何か変更がありましたか?ドキュメントが言うように:

これにより、リクエストを送信し、結果を気にする必要がなくなります。

次の単体テストを試すことができます(テストベッドを使用)。

@ndb.tasklet
def raiseSomething():
    yield ndb.Key('foo','bar').get_async()
    raise Exception()

@ndb.toplevel
def callRaiseSomething():
    future = raiseSomething()
    return "hello"

response = callRaiseSomething()
self.assertEqual(response, "hello")

このテストは合格です。NDBは警告をログに記録します:「中断されたジェネレータraiseSomething(tests.py:90)はException()を発生させました」が、例外を再発生させません。

ndb.toplevelはRPCを待機するだけで、実際の結果は何もしません。装飾された関数自体がタスクレットの場合、最初にget_result()を呼び出します。この時点で、例外が発生します。次に、残りの「孤立した」RPCを待機し、例外が発生した場合にのみログに記録します。

だから私の応答は次のとおりです:リクエストは成功します(200を返します)

于 2013-08-15T13:42:16.857 に答える