私はPython 3.4.3を使用して、複数のURLに定期的にリクエストを送信しています。これが私が書いたコルーチンです (コードを簡素化するためにいくつかのエラー処理を省略しました):
@asyncio.coroutine
def ping(url, interval, session, *, loop):
while True:
try:
with aiohttp.Timeout(interval):
resp = yield from session.get(url)
resp.close()
except asyncio.TimeoutError:
# continue sending requests anyway
continue
yield from asyncio.sleep(interval)
を使用して複数のping
コルーチンを開始してasyncio.gather
います。しかし、サーバーの応答が長すぎると、InvalidStateError
例外が発生することがあります。
Exception in callback <bound method Future.set_result of Future<CANCELLED>>(None,)
handle: Handle(<bound method Future.set_result of Future<CANCELLED>>, (None,))
Traceback (most recent call last):
File "/usr/lib/python3.4/asyncio/events.py", line 39, in _run
self._callback(*self._args)
File "/usr/lib/python3.4/asyncio/futures.py", line 298, in set_result
raise InvalidStateError('{}: {!r}'.format(self._state, self))
asyncio.futures.InvalidStateError: CANCELLED: Future<CANCELLED>
スクリプトは引き続き機能しますが、このトレースバックを黙らせるにはどうすればよいですか? それはバグですか、それとも私が間違っていることですか?
私が持っている唯一の考えは、Webサーバーが最終的に応答するときに、asyncio(またはaiohttp)Future
がすでにキャンセルされた結果にresultを設定しようとすることです。
編集:
ping
そのコルーチンを開始する方法は次のとおりです。
@asyncio.coroutine
def main(loop, rules, session):
tasks = [ping(url, interval, session, loop=loop)
for url, interval in rules]
try:
yield from asyncio.gather(*tasks, loop=loop)
except Exception:
print('Cancelled!', file=sys.stderr)
traceback.print_exc()
if __name__ == '__main__':
rules = [('http://localhost:8080/1/', 5),
('http://localhost:8080/2/', 10)]
loop = asyncio.get_event_loop()
try:
conn = aiohttp.TCPConnector(verify_ssl=False)
with aiohttp.ClientSession(connector=conn) as session:
loop.run_until_complete(main(loop=loop,
rules=rules,
session=session))
except KeyboardInterrupt:
print('Interrupted. Exiting', file=sys.stderr)