2017-06-23 6 views
0

いくつかの珍しい制約のため、応答を返す前に別のサービスからコールバックURLを同期的に待つ必要があります。現在、私は似た何かを持っている:Python 3 asyncioでコールバックを同期して待機する方法を実装しますか?

ROUTE = '/operation' 
async def post(self): 
    ##SOME OPERATIONS## 
    post_body = { 'callbackUrl' : 'myservice.com/cb' } 
    response = await other_service.post('/endpoint') 
    global my_return_value 
    my_return_value = None 
    while not my_return_value: 
     pass 
    return self.make_response(my_return_value) 

それから私は、コールバックURLを処理するための方法を持っているようなもの:このコードの問題は、それが永遠にさえ永遠にそのwhileループの中に閉じ込めてしまうことです

ROUTE = '/cb' 
async def post(self): 
    ##OPERATIONS### 
    global my_return_value 
    my_return_value = some_value 
    return web.json_response() 

をコールバックURLが呼び出された場合。私はこれを行うには良い方法があると思うが、私はそれについて行く方法やgoogleのためにどのように行くのかわからない。何か案は?

ありがとうございます!ただ、クイックスキャン

+1

のようなものがありますが、これはおそらくより良い方法ですが、あなたの欠点は間違いないと思います'グローバルmy_return_value'コールバックルート。 – smarx

+0

なぜ、 'other_service.post()'が '(some_value、web.json_response())'タプルを返さないのでしょうか? –

+0

そして、投稿を呼び出した後で 'my_return_value = None'を設定しているので無限ループになります。あなたのコルーチンは*まだ順調です*、 '/ operation'' post()'コルーチンは 'response = await other_service.post( '/ endpoint')'が返るまで続かないでしょう。 –

答えて

1

は、私はあなたが

while not my_return_value: 
    pass 

Pythonはコールバック関数に対処する時間がありませんし、トラップされる中に閉じ込められていると思います。何が必要

while not my_return_value: 
    await asyncio.sleep(1) 

(またはあなたがミリ秒の遅延をしたくない場合は、あなたもasyncio.sleep(0)を行うことができます)です。

も、よりよい方法はされるだろう(そして今、私はメモリから書いている、保証しない...):これまで複数ある場合はいずれかの方法は非常に多くを破るだろうということが

my_return_value = asyncio.get_event_loop().create_future() 
await my_return_value 
return self.make_response(my_return_value.result()) 


async def post(self): 
    ##OPERATIONS### 
    my_return_value.set_result(some_value) 
    return web.json_response() 

注意このシステムの同時使用。それは非常に壊れやすい感じ!多分よりよい:

ROUTE = '/operation' 
my_return_value = {} 

async def post(self): 
    ##SOME OPERATIONS## 
    token = "%016x" % random.SystemRandom().randint(0, 2**128) 
    post_body = { 'callbackUrl' : 'myservice.com/cb?token='+token } 
    response = await other_service.post('/endpoint') 
    my_return_value[token] = asyncio.get_event_loop().create_future() 
    await my_return_value[token] 
    result = my_return_value[token].result() 
    del my_return_value[token] 
    return self.make_response(result) 

async def post(self): 
    ##OPERATIONS### 
    token = self.arguments("token") 
    my_return_value[token].set_result(some_value) 
    return web.json_response() 

今すぐ上に桜は、コールバックが起こらない場合は、しばらくして、タイムアウト後の将来をキャンセルしmy_return_valueにエントリをクリーンアップするでしょうタイマーだろう。また、最後の提案を行っている場合は、callback_future_by_token ... callback_future_by_token ...

+0

私の現在の解決策は、乱数生成の代わりにuuidを使用する以外は、あなたの2番目のように見えます。しかし、私はFuturesの使用に自信がないので、これは特に役立ちます。 – Matt

関連する問題