Package: async-stagger
Quick, what’s the situation?To get all the benefits of Happy Eyeballs connection establishment algorithm,
simply useasync_stagger.open_connectionlike you would useasyncio.open_connection:reader, writer = await async_stagger.open_connection('www.example.com', 80)Now your connections are more dual-stack friendly and will complete faster!
A replacement forloop.create_connectionis also provided.The long versionWhat is Happy Eyeballs, and why should I use it?Happy Eyeballs is an algorithm for establishing TCP connections to destinations
specified by host names. It is described inRFC 6555andRFC 8305. The
primary benefit is that when host name resolution returns multiple addresses,
and some of the address are unreachable, Happy Eyeballs will establish the
connection much faster than conventional algorithms. For more information,
check theWikipedia article on Happy Eyeballs.Python’s standard library provides several high-level methods of establishing
TCP connections towards a host name: Thesocketmodule hassocket.create_connection,
andasynciohasloop.create_connectionandasyncio.open_connection.
By default,
these methods have the same behavior when a host name resolves to several IP
addresses: they try to connect to the first address in the list,
and only after the attempt fails (which may take tens of seconds) will
the second one be tried, and so on. In contrast, the Happy Eyeballs algorithm
will start an attempt with the second IP address in parallel to the first one
hasn’t completed after some time, typically around 300 milliseconds.
As a result several attempts may be in flight at the same time, and whenever
one of the attempts succeed, all other connections are cancelled, and the
winning connection is used.
This means a much shorter wait before one of the IP addresses connect
successfully.Happy Eyeballs is particularly important for dual-stack clients, when some hosts
may have resolvable IPv6 addresses that are somehow unreachable.Starting from Python 3.8, stockasyncioalso supports Happy Eyeballs.
See below for a comparison.What doesasync_staggerhas to offer?async_staggerprovidesopen_connectionandcreate_connectionwith Happy Eyeballs support. They are mostly drop-in
replacements for theirasynciocounterparts, and support most existing
arguments.
(There are small differences:create_connectiontakes
aloopargument instead of being a method on an event loop.
Also, these two methods do not support thesockargument.)
Another public coroutinecreate_connected_sockreturns a connectedsocket.socketobject.
Check the documentation for details.These methods implements many features specified inRFC 8305Happy Eyeballs
v2, which extends and obsoletesRFC 6555. In particular, asynchronous
address resolution, destination address interleaving by family and staggered
connection attempts are implemented.Happy Eyeballs sounds great! I want to use similar logic somewhere else!You’re in luck!async_staggeractually exposes the underlying scheduling
logic as a reusable block:staggered_race. It can be use when:There are several ways to achieve one goal. Some of the ways may fail, but
you have to try it to find out.Making attempts strictly in sequence is too slow.You want to parallelize, but also don’t want to start the attempts all
at the same time. Maybe you want to give preference to some of the attempts,
so they should be started earlier and given more time to complete. Maybe you
want to avoid straining the system with simultaneous attempts.An attempt done half-way can be rolled back safely.Where can I get it?async_staggerrequires Python 3.6 or later.
(v0.2.0 onwards uses more new features in 3.6 such as async generators and
async comprehensions, so it will probably require more than cosmetic changes
to make it run on 3.5.)
It does not have any external dependencies.
Install it from PyPI the usual way:pip install async-staggerThe documentation can be found here:http://async-stagger.readthedocs.io/en/latest/This project is under active development, and APIs may change in the future.
Check out the Changelog in the documentation.This project is licensed under the MIT license.Python 3.8 Has Native Happy Eyeballs NowI contributed an implementation of Happy Eyeballs to upstreamasyncio,
and it landed in Python 3.8: seethe docsfor details.That implementation is essentially an early version of this package,
so it lacks these features:Async address resolutionDetailed exception reportThelocal_addrsargument (as opposed tolocal_addr)Still, it should be sufficient for most scenarios, and it’s right there in the standard library.Miscellaneous RemarksAsynchronous address resolution is added in v0.2.1. With that, I feel that
the package should be fairly feature-complete.I have implemented Happy Eyeballs-like algorithms in some of my other projects,
and this module reflects the things I have learned. However I have yet to
eat my own dog food and actually import this module from those other projects.
I would love to hear people’s experience using this module in real world
conditions.bpo-31861talks about adding nativeaiterandanextfunctions either as builtins or to theoperatormodule. Well, I want them NAO!!!one!!!eleventy!! So I borrowed the
implementations from that bpo and put them in theaitertoolssubmodule.
I have only kept the one-argument forms; In particular, the two-argumentiterfunction is so disparate from the one-argument version, that I don’t
think they belong to the same function at all, and there really shouldn’t be
a need foraiterto emulate that behavior.AcknowledgmentsThe Happy Eyeballs scheduling algorithm implementation is inspired bythe implementation in trio.