Missing support for `interleave` and `happy_eyeballs_delay` in `create_connection`
- uvloop version: 0.15.2
- Python version: 3.8.5
- Platform: Ubuntu 20.04 amd64
-
Can you reproduce the bug with
PYTHONASYNCIODEBUGin env?: Not tested. -
Does uvloop behave differently from vanilla asyncio? How?: Yes, fails if
interleaveand/orhappy_eyeballs_delayis set withcreate_connection.
asyncio loop.create_connection supports the interleave and happy_eyeballs_delay keyword arguments to enable RFC 8305 "Happy Eyeballs" IPv6-to-IPv4 fallback since Python 3.8. The arguments are documented here: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.create_connection
The corresponding function in uvloop does not accept these arguments. These would be nice to have because I'm working on a server that proxies requests to external third-party servers which occasionally have a broken IPv6 configuration and traditional connect timeout behavior causes quite a bit of delay.
This looks interesting to me. I've dug around for a few days now, but I've never worked with the cython.
I've read this RFC https://tools.ietf.org/html/rfc8305.html and basically try to backport this https://github.com/python/cpython/pull/7237/files
If someone has any tips or guidance I would really appreciate that.
I haven't implemented this myself and am also unfamiliar with Cython so can't really help. We managed to work around the problem with selective application of native asyncio, since this problem only affected a relative low-traffic portion of the app.
Hey @1st1 @fantix I think I really want to dig into this and implement it, but I want to double-check if it's something you will be willing to accept?
We're obviously willing to accept such a PR.
Seems like this is doable. From what I've seen, the scope of the feature would apply to changes to loop.pyx and loop.pyi. Hypothetically, it might need to satisfy:
import uvloop
import asyncio
from typing import *
async def leave_happy(
host,
port,
happy_eyeballs_delay: Optional[float] = None,
interleave: Optional[int] = None):
if interleave is not None:
if not interleave & 1:
raise ValueError("`interleave` argument must be non-negative")
else:
interleave = 0
loop = asyncio.get_running_loop()
(transp, pro) = await loop.create_connection(
uvloop.EventLoopPolicy,
host=host,
port=port,
happy_eyeballs_delay=happy_eyeballs_delay,
interleave=interleave
)
return (transp, pro)
async def main():
await leave_happy(host="127.0.0.1", port=2160)
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
asyncio.run(main())
We're obviously willing to accept such a PR.
I briefly compared Lib/asyncio/base_events.py against uvloop/handles/handle.pyx, and believe I found the appropriate entrypoint to inject this logic. Since loop.create_server shares a similar signature with loop.create_connection, does it seem valid to apply this here?