Aiohttp: `aiohttp.Timeout` raises an RuntimeError inside asyncio based tornado app.

Created on 16 May 2016  路  8Comments  路  Source: aio-libs/aiohttp

I use aiohttp as a client inside tornado,but the aiohttp.Timeout raises an RuntimeError.

code example:

import asyncio

import aiohttp

import tornado.web
from tornado.platform.asyncio import AsyncIOMainLoop

class MainHandler(tornado.web.RequestHandler):
    async def get(self):
        with aiohttp.Timeout(1):
            result = await aiohttp.get("www.github.com")
        self.write(result)

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

if __name__ == "__main__":
    AsyncIOMainLoop().install()
    app = make_app()
    app.listen(8888)
    asyncio.get_event_loop().run_forever()

the exception is:

Uncaught exception GET / (::1)
HTTPServerRequest(protocol='http', host='localhost:8888', method='GET', uri='/', version='HTTP/1.1', remote_ip='::1', headers={'Host': 'localhost:8888', 'Connection': 'keep-alive', 'If-None-Match': '"e02aa1b106d5c7c6a98def2b13005d5b84fd8dc8"', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36', 'Accept-Language': 'en,zh-CN;q=0.8,zh;q=0.6,ja;q=0.4,zh-TW;q=0.2', 'Upgrade-Insecure-Requests': '1', 'Accept-Encoding': 'gzip, deflate, sdch'})
Traceback (most recent call last):
  File "/Users/justfly/Developer/envs/new_tornado_env/lib/python3.5/site-packages/tornado/web.py", line 1445, in _execute
    result = yield result
  File "/Users/justfly/Developer/envs/new_tornado_env/lib/python3.5/site-packages/tornado/gen.py", line 1008, in run
    value = future.result()
  File "/Users/justfly/Developer/envs/new_tornado_env/lib/python3.5/site-packages/tornado/concurrent.py", line 232, in result
    raise_exc_info(self._exc_info)
  File "<string>", line 3, in raise_exc_info
  File "/Users/justfly/Developer/envs/new_tornado_env/lib/python3.5/site-packages/tornado/gen.py", line 282, in wrapper
    yielded = next(result)
  File "<string>", line 6, in _wrap_awaitable
  File "test.py", line 11, in get
    with aiohttp.Timeout(1):
  File "/Users/justfly/Developer/envs/new_tornado_env/lib/python3.5/site-packages/aiohttp/helpers.py", line 478, in __enter__
    raise RuntimeError('Timeout context manager should be used '
RuntimeError: Timeout context manager should be used inside a task
invalid outdated sprint

Most helpful comment

To address @imjustfly's issue: Many asyncio methods assume that the whole world is asyncio, and don't work well when mixing asyncio and Tornado. The Tornado versions of these methods are generally better about this, so I'd recommend using tornado.gen.with_timeout instead:

from datetime import timedelta
from tornado.gen import with_timeout, convert_yielded

result = await with_timeout(timedelta(seconds=1),
    convert_yielded(aiohttp.get('http://www.example.com')))

(The convert_yielded call is because Tornado isn't perfect about accepting asyncio coroutines either. This will go away in the next release of Tornado).

All 8 comments

I'll start looking into this one

@asvetlov tornado doesn't update asyncio.tasks.Task._current_tasks so this context manager likely can't be made to work in tornado.

Yes, aiohttp.Timeout work only inside an asyncio task context.
aiohttp creates a task for handling web requests by server api.
Tornado uses another technique not relying on tasks.

@bdarnell I believe the issue cannot be solved but want to let you know about it's existance at least.

aiohttp.Timeout has the same implementation as asyncio.timeout but exists here because aiohttp has much shorter release cycle.

Ugh. Yeah, that's relying on asyncio implementation details and cannot be used in any application or library that hopes to be portable across coroutine runners.

To address @imjustfly's issue: Many asyncio methods assume that the whole world is asyncio, and don't work well when mixing asyncio and Tornado. The Tornado versions of these methods are generally better about this, so I'd recommend using tornado.gen.with_timeout instead:

from datetime import timedelta
from tornado.gen import with_timeout, convert_yielded

result = await with_timeout(timedelta(seconds=1),
    convert_yielded(aiohttp.get('http://www.example.com')))

(The convert_yielded call is because Tornado isn't perfect about accepting asyncio coroutines either. This will go away in the next release of Tornado).

@bdarnell Got it ! Thank you.

This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a [new issue] for
related bugs.

If you feel like there's important points made in this discussion,
please include those exceprts into that [new issue].

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JulienPalard picture JulienPalard  路  3Comments

Smosker picture Smosker  路  3Comments

alxpy picture alxpy  路  5Comments

asvetlov picture asvetlov  路  4Comments

JoseKilo picture JoseKilo  路  3Comments