私のようなハンドラとaiohttpウェブサーバアプリケーションがあります。CancelledErrorはどのように典型的なaiohttp Webサーバーで処理する必要がありますか?
app["db"]
がプールされたリソースのいくつかの種類である
async def handler(request):
async with request.app["db"].acquire() as db:
row = await query(db)
return aiohttp.web.json_response(row)
(aiopg
、aioredis
を、今は関係ありません)。これは今日まで素晴らしい仕事をしていました。
File "/visio-longer/visio_longer/views/communicate/__init__.py", line 81, in legacy_communicate
async with request.app["db"].acquire() as db:
:ここ
[2017-05-21 17:58:24,254] ERROR [aiohttp.server] Error handling request
Traceback (most recent call last):
File "/virtualenv/lib/python3.6/site-packages/aiohttp/web_server.py", line 61, in handle_request
resp = yield from self._handler(request)
File "/virtualenv/lib/python3.6/site-packages/aiohttp/web.py", line 249, in _handle
resp = yield from handler(request)
File "/visio-longer/visio_longer/views/communicate/__init__.py", line 81, in legacy_communicate
async with request.app["db"].acquire() as db:
File "/virtualenv/src/aiopg/aiopg/utils.py", line 140, in __aenter__
self._conn = yield from self._coro
File "/virtualenv/src/aiopg/aiopg/sa/engine.py", line 162, in _acquire
raw = yield from self._pool.acquire()
File "/virtualenv/src/aiopg/aiopg/utils.py", line 67, in __iter__
resp = yield from self._coro
File "/virtualenv/src/aiopg/aiopg/pool.py", line 168, in _acquire
with (yield from self._cond):
File "/usr/lib/python3.6/asyncio/locks.py", line 67, in __iter__
yield from self.acquire()
File "/usr/lib/python3.6/asyncio/locks.py", line 176, in acquire
yield from fut
concurrent.futures._base.CancelledError
キーポイントは、プールからデータベース接続を取得しながら、それが(タイムアウトによってクライアントの接続が切断)をCancelledError
を受けていたあるように、すべてのクライアントがタイムアウトとアプリケーションログで切断開始した理由もなく痕跡を充填
私はプールの状態(size
とfreesize
)を5秒ごとに印刷していたコルーチンを実行していましたが、現在プールには十分な空き接続があります!
調査の時間は、プールのコンテキストマネージャ__atexit__
を実行している間にCancelledError
を受信するとプールへの接続を戻すプロセスを中止し、プールの誤動作を招いたという理論に終わりました。私はasyncpg
でその動作を修正しているcommitを見つけました。aioredis
には同様のコードが含まれています。私はawkward-looking fixをaiopg
にしました。これは役に立たなかった。私はまだaioredis
とaiopg
の両方から同じエラーが出ていた。
asyncio.shield
で接続プールを使用するコードのすべての部分をラップすることにより、
async def handler(request):
async with request.app["db"].acquire() as db:
row = await query(db)
return aiohttp.web.json_response(row)
を交換することで解決状況:
async def handler(request):
async def process():
async with request.app["db"].acquire() as db:
row = await query(db)
return aiohttp.web.json_response(asyncio.shield(process(row)))
中断された要求はまだ取得し帰国を含む(それらの末端に処理されたので、プールへのリソース)。
これはこの方法であるはずですか?今度は私のコードがひどく見えて、次回はプールをasyncio.shield
で包むのを忘れないという保証はありません。この問題を解決する適切な方法は何ですか(明らかにライブラリはそれ自体を修正できません)。
https://vorpus.org/blog/control -c-handling-in-python-and-trio/interestingです。 –