Skip to content

asyncio.loop.sendfile(fallback=False) raises inconsistent exceptions when native sendfile is unavailable #152099

Description

@tarasko

Bug report

Bug description:

asyncio.loop.sendfile() does not reliably report native sendfile unavailability when fallback=False.

The documentation says:

Raise SendfileNotAvailableError if the system does not support the sendfile syscall and fallback is False.

However, the actual exception depends on the transport mode:

  • TRY_NATIVE transport where native sendfile fails:
    raises SendfileNotAvailableError
  • FALLBACK transport, such as SSL/TLS:
    raises RuntimeError("fallback is disabled and native sendfile is not supported ...")
  • unsupported transport:
    raises RuntimeError("sendfile is not supported ...")

This makes it hard for callers to reliably detect that native sendfile is unavailable. Catching RuntimeError is too broad, because it can also indicate unrelated states such as a closing transport or an unsupported
transport object.

For example, in aiohttp there is a project specific sendfile fallback implementation, which is more efficient than asyncio's fallback.
I did a small PR aio-libs/aiohttp#12945
which illustrates performance difference but there is no reliable way to detect that loop.sendfile can't be used with a particular transport. So I had to use private members from asyncio to do that.

It would be nice to just have the following logic:

try:
    loop.sendfile(transport, ..., fallback=False)
except asyncio.SendfileNotAvailableError:
     _sendfile_fallback(...)

But, it doesn't work for at least SSL transports.

Suggested fix:

Always raise SendfileNotAvailableError when native sendfile for transport can't be used and fallback=False

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions