Skip to content

Timeouts checked once a second (?) #4850

Closed
@haizaar

Description

🐞 Describe the bug

aiohttp.ClientTimeout.total is annotated to accept floats, yet my observations are that timeout condition is checked once a second. Is it a bug or feature? E.g. requests library does not have this limitation and easily works with 0.01 timeouts in my tests. I realize that sub-second timeouts are quite synthetic, but very useful for tests.

💡 To Reproduce
aiohttp 3.6.2 on Ubuntu 18.04 amd64 with CPython 3.8.3.

Consider the below code:

import asyncio
import socket
import sys
import time

import aiohttp
from aiohttp import web


async def hello(request):
    await asyncio.sleep(10)
    return web.Response(text="Hello, world")


async def run_client(port: int, timeout: float):
    async with aiohttp.ClientSession() as session:
        while True:
            start = time.monotonic()
            try:
                await session.get(f"http://localhost:{port}/",
                                  timeout=aiohttp.ClientTimeout(total=timeout))
            except asyncio.TimeoutError:
                pass
            took = time.monotonic() - start
            print(f"expected={timeout}, took={took:.3f}, skew={took-timeout:.3f}")


async def amain(timeout: float):
    app = web.Application()
    app.add_routes([web.get('/', hello)])
    runner = web.AppRunner(app)
    await runner.setup()

    sock = socket.socket(socket.AF_INET, type=socket.SOCK_STREAM)
    sock.bind(("localhost", 0))
    _, port = sock.getsockname()

    site = web.SockSite(runner=runner, sock=sock)
    await site.start()

    await run_client(port, timeout)


if __name__ == "__main__":
    asyncio.run(amain(float(sys.argv[1])))

No matter what the timeout value is, the actual timeout is always in multiples of 1 second as you can see in the took value below:

$ python /tmp/timeout-bug.py 0.1
expected=0.1, took=0.726, skew=0.626
expected=0.1, took=1.000, skew=0.900
expected=0.1, took=1.000, skew=0.900
python /tmp/timeout-bug.py 0.8
expected=0.8, took=1.414, skew=0.614
expected=0.8, took=0.999, skew=0.199
expected=0.8, took=1.000, skew=0.200
expected=0.8, took=1.001, skew=0.201
python /tmp/timeout-bug.py 1.1
expected=1.1, took=1.473, skew=0.373
expected=1.1, took=2.000, skew=0.900
expected=1.1, took=2.000, skew=0.900
expected=1.1, took=2.000, skew=0.900
python /tmp/timeout-bug.py 2.1
expected=2.1, took=2.158, skew=0.058
expected=2.1, took=2.999, skew=0.899
expected=2.1, took=3.001, skew=0.901
expected=2.1, took=2.998, skew=0.898

💡 Expected behavior
Is this intentional or a bug?


📋 **Your version of the Python**
<!-- Attach your version of the Python. -->
```console
$ python --version
Python 3.8.3
...

📋 Your version of the aiohttp/yarl/multidict distributions

$ python -m pip show aiohttp
Name: aiohttp
Version: 3.6.2
Summary: Async http client/server framework (asyncio)
Home-page: https://github.com/aio-libs/aiohttp
Author: Nikolay Kim
Author-email: fafhrd91@gmail.com
License: Apache 2
Location: /home/.../lib/python3.8/site-packages
Requires: multidict, chardet, async-timeout, attrs, yarl
Required-by: 
$ python -m pip show multidict
Name: aiohttp
Version: 3.6.2
Summary: Async http client/server framework (asyncio)
Home-page: https://github.com/aio-libs/aiohttp
Author: Nikolay Kim
Author-email: fafhrd91@gmail.com
License: Apache 2
Location: /home/.../lib/python3.8/site-packages
Requires: multidict, chardet, async-timeout, attrs, yarl
Required-by: 
$ python -m pip show multidict
Name: multidict
Version: 4.7.6
Summary: multidict implementation
Home-page: https://github.com/aio-libs/multidict
Author: Andrew Svetlov
Author-email: andrew.svetlov@gmail.com
License: Apache 2
Location: /home/.../lib/python3.8/site-packages
Requires: 
Required-by: yarl, aiohttp
$ python -m pip show yarl
Name: yarl
Version: 1.4.2
Summary: Yet another URL library
Home-page: https://github.com/aio-libs/yarl/
Author: Andrew Svetlov
Author-email: andrew.svetlov@gmail.com
License: Apache 2
Location: /home/.../lib/python3.8/site-packages
Requires: idna, multidict
Required-by: aiohttp

📋 Additional context

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions