{ "info": { "author": "twisteroid ambassador", "author_email": "twisteroid.ambassador@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "async_stagger: Happy Eyeballs in ``asyncio``\n############################################\n\nQuick, what's the situation?\n============================\n\nTo get all the benefits of Happy Eyeballs connection establishment algorithm,\nsimply use ``async_stagger.open_connection`` like you would use\n``asyncio.open_connection``::\n\n reader, writer = await async_stagger.open_connection('www.example.com', 80)\n\nNow your connections are more dual-stack friendly and will complete faster!\nA replacement for ``loop.create_connection`` is also provided.\n\nThe long version\n================\n\nWhat is Happy Eyeballs, and why should I use it?\n------------------------------------------------\n\nHappy Eyeballs is an algorithm for establishing TCP connections to destinations\nspecified by host names. It is described in :rfc:`6555` and :rfc:`8305`. The\nprimary benefit is that when host name resolution returns multiple addresses,\nand some of the address are unreachable, Happy Eyeballs will establish the\nconnection much faster than conventional algorithms. For more information,\ncheck the `Wikipedia article on Happy Eyeballs`_.\n\n.. _Wikipedia article on Happy Eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs\n\nPython's standard library provides several high-level methods of establishing\nTCP connections towards a host name: The **socket** module has\n``socket.create_connection``,\nand **asyncio** has ``loop.create_connection`` and ``asyncio.open_connection``.\nThese methods have the same behavior when a host name resolves to several IP\naddresses: they try to connect to the first address in the list,\nand only after the attempt fails (which may take tens of seconds) will\nthe second one be tried, and so on. In contrast, the Happy Eyeballs algorithm\nwill start an attempt with the second IP address in parallel to the first one\nhasn't completed after some time, typically around 300 milliseconds.\nAs a result several attempts may be in flight at the same time, and whenever\none of the attempts succeed, all other connections are cancelled, and the\nwinning connection is used.\nThis means a much shorter wait before one of the IP addresses connect\nsuccessfully.\n\nHappy Eyeballs is particularly important for dual-stack clients, when some hosts\nmay have resolvable IPv6 addresses that are somehow unreachable.\n\n\nWhat does ``async_stagger`` has to offer?\n-----------------------------------------\n\n``async_stagger`` provides ``open_connection`` and\n``create_connection`` with Happy Eyeballs support. They are mostly drop-in\nreplacements for their ``asyncio`` counterparts, and support most existing\narguments.\n(There are small differences: ``create_connection`` takes\na *loop* argument instead of being a method on an event loop.\nAlso, these two methods do not support the *sock* argument.)\nAnother public coroutine ``create_connected_sock`` returns a connected\n``socket.socket`` object.\nCheck the documentation for details.\n\nThese methods implements many features specified in :rfc:`8305` Happy Eyeballs\nv2, which extends and obsoletes :rfc:`6555`. In particular, asynchronous\naddress resolution, destination address interleaving by family and staggered\nconnection attempts are implemented.\n\n\nHappy Eyeballs sounds great! I want to use similar logic somewhere else!\n------------------------------------------------------------------------\n\nYou're in luck! ``async_stagger`` actually exposes the underlying scheduling\nlogic as a reusable block: ``staggered_race``. It can be use when:\n\n* There are several ways to achieve one goal. Some of the ways may fail, but\n you have to try it to find out.\n\n* Making attempts strictly in sequence is too slow.\n\n* You want to parallelize, but also don't want to start the attempts all\n at the same time. Maybe you want to give preference to some of the attempts,\n so they should be started earlier and given more time to complete. Maybe you\n want to avoid straining the system with simultaneous attempts.\n\n* An attempt done half-way can be rolled back safely.\n\n\nWhere can I get it?\n-------------------\n\n``async_stagger`` requires Python 3.6 or later.\n(v0.2.0 onwards uses more new features in 3.6 such as async generators and\nasync comprehensions, so it will probably require more than cosmetic changes\nto make it run on 3.5.)\nIt does not have any external dependencies.\nInstall it from PyPI the usual way::\n\n pip install async-stagger\n\nThe documentation can be found here:\nhttp://async-stagger.readthedocs.io/en/latest/\n\nThis project is under active development, and APIs may change in the future.\nCheck out the Changelog in the documentation.\n\nThis project is licensed under the MIT license.\n\n\nMiscellaneous Remarks\n=====================\n\nAsynchronous address resolution is added in v0.2.1. With that, I feel that\nthe package should be fairly feature-complete.\n\nI have implemented Happy Eyeballs-like algorithms in some of my other projects,\nand this module reflects the things I have learned. However I have yet to\neat my own dog food and actually import this module from those other projects.\nI would love to hear people's experience using this module in real world\nconditions.\n\n`bpo-31861 `_ talks about adding native\n``aiter`` and ``anext`` functions either as builtins or to the ``operator``\nmodule. Well, I want them NAO!!!one!!!eleventy!! So I borrowed the\nimplementations from that bpo and put them in the ``aitertools`` submodule.\nI have only kept the one-argument forms; In particular, the two-argument\n``iter`` function is so disparate from the one-argument version, that I don't\nthink they belong to the same function at all, and there really shouldn't be\na need for ``aiter`` to emulate that behavior.\n\n\nAcknowledgments\n===============\n\nThe Happy Eyeballs scheduling algorithm implementation is inspired by\n`the implementation in trio`__.\n\n__ https://github.com/python-trio/trio/pull/145/files\n\n\n\n", "description_content_type": "text/x-rst", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/twisteroidambassador/async_stagger", "keywords": "happy-eyeballs dual-stack tcp", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "async-stagger", "package_url": "https://pypi.org/project/async-stagger/", "platform": "", "project_url": "https://pypi.org/project/async-stagger/", "project_urls": { "Documentation": "http://async_stagger.readthedocs.io", "Homepage": "https://github.com/twisteroidambassador/async_stagger" }, "release_url": "https://pypi.org/project/async-stagger/0.3.0/", "requires_dist": [ "pytest ; extra == 'test'", "pytest-asyncio ; extra == 'test'", "pytest-mock ; extra == 'test'" ], "requires_python": ">=3.6", "summary": "Happy eyeballs and underlying scheduling algorithm in asyncio", "version": "0.3.0" }, "last_serial": 4621263, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "09c98583a230dd883aea9705cde33bf8", "sha256": "4ca3490fc0a346f3999ee672b6f0eea28460b6a19b47a62a67f979aee0e2bd92" }, "downloads": -1, "filename": "async_stagger-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "09c98583a230dd883aea9705cde33bf8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 10963, "upload_time": "2018-05-11T15:22:09", "url": "https://files.pythonhosted.org/packages/00/a5/fc1cda40c4e4a6f5b8b9fe593814a4ba521d150051a244e0e0bbad5b890b/async_stagger-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "91746b6a2d3aa3362f9a16ae92308490", "sha256": "944ee70e5130fca9ff90e32b3477b3c36699b99cf3bd9a94cb6307965e88defc" }, "downloads": -1, "filename": "async_stagger-0.1.0.tar.gz", "has_sig": false, "md5_digest": "91746b6a2d3aa3362f9a16ae92308490", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 9930, "upload_time": "2018-05-11T15:22:11", "url": "https://files.pythonhosted.org/packages/c0/a8/527def9328ce1cc61251bfa206787c6958331b39bde3613dcb7ad432a38d/async_stagger-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "3ccc3ce35a824a8b070883794b47da86", "sha256": "314ebf449f726a5d2a8db47463f74972b7a7acb8f4309cefb7c659e733d4f3ae" }, "downloads": -1, "filename": "async_stagger-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "3ccc3ce35a824a8b070883794b47da86", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 11018, "upload_time": "2018-05-12T04:51:29", "url": "https://files.pythonhosted.org/packages/b1/6d/4d8d39c5868441166b020a3301138fc121c4c7f0bbadba42313756625a72/async_stagger-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c0f0bf3a4d74c54d80960e3cab865510", "sha256": "c6f48b056ee9ae545b3c666a21c74ba38c74bee6755d9a4185fd763b497a5d33" }, "downloads": -1, "filename": "async_stagger-0.1.1.tar.gz", "has_sig": false, "md5_digest": "c0f0bf3a4d74c54d80960e3cab865510", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 9997, "upload_time": "2018-05-12T04:51:31", "url": "https://files.pythonhosted.org/packages/2b/b5/f9400eaa21559875b80843f56a59683dd185e733154a362a94556dd3c377/async_stagger-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "468e59b2b8b5d133ae39a74dff9c37c6", "sha256": "528d41dc451f98f5ac18822c3da792436fce9d88d0fe8d5bde7736438229403f" }, "downloads": -1, "filename": "async_stagger-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "468e59b2b8b5d133ae39a74dff9c37c6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 11087, "upload_time": "2018-06-18T03:44:43", "url": "https://files.pythonhosted.org/packages/29/43/5d001af42d3a5da421bf6970a6c9f20574af606eb8fa055ed71f0739f049/async_stagger-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1d5a6653036cb486db1a9ad84b546fd4", "sha256": "f7de85e13243a12a16d02fb6e8214b928ecaa525333ae37e615d01d66aaaeb06" }, "downloads": -1, "filename": "async_stagger-0.1.2.tar.gz", "has_sig": false, "md5_digest": "1d5a6653036cb486db1a9ad84b546fd4", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 10061, "upload_time": "2018-06-18T03:45:35", "url": "https://files.pythonhosted.org/packages/28/91/350f11b44e749830374becd8a482b027f7ad58404a415afe95f6dca286fa/async_stagger-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "77675fc67b8c45f0c93fa481d0a09336", "sha256": "ee89d6204f682d7560b57fc08d6f80a5dfeaa56c1dc33b5a61fb961df71269b8" }, "downloads": -1, "filename": "async_stagger-0.1.3-py3-none-any.whl", "has_sig": false, "md5_digest": "77675fc67b8c45f0c93fa481d0a09336", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 11476, "upload_time": "2018-07-31T15:22:46", "url": "https://files.pythonhosted.org/packages/cb/26/e102e19c2fcff2a946cfa8b3208495a78bf61e07aabb9f08b0a2497f1b16/async_stagger-0.1.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "308b74235155fa074143fa2fd9e610bb", "sha256": "95e4d2563466ec88534540b59a7b26f1a3bf4476aace1c90b212f5741c4d5743" }, "downloads": -1, "filename": "async_stagger-0.1.3.tar.gz", "has_sig": false, "md5_digest": "308b74235155fa074143fa2fd9e610bb", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 10410, "upload_time": "2018-07-31T15:22:49", "url": "https://files.pythonhosted.org/packages/17/5c/e91b6e63cf082794a3581ddfd653348fd8c00b2ae06b3067b916166eb5f8/async_stagger-0.1.3.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "9f94aadbe119ac4a3d56b0e694fa1acf", "sha256": "c920a68af79db8c89e0c361d97702a1d3b29ff5cd46b2c4b26383f5ce8a8c67f" }, "downloads": -1, "filename": "async_stagger-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "9f94aadbe119ac4a3d56b0e694fa1acf", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 17676, "upload_time": "2018-09-01T15:15:10", "url": "https://files.pythonhosted.org/packages/5f/7c/e0a4b775448b11833463120097c75568f2b0a9c4a851d2b5b27fdcd8d080/async_stagger-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3bd4c37b15be7de304ff180a250e8c56", "sha256": "d1ccf38cc312252e466df3e141ae57b34c04ecc717e2bb6abc3d865ed8036f83" }, "downloads": -1, "filename": "async_stagger-0.2.0.tar.gz", "has_sig": false, "md5_digest": "3bd4c37b15be7de304ff180a250e8c56", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 14713, "upload_time": "2018-09-01T15:15:11", "url": "https://files.pythonhosted.org/packages/8d/6f/890f75239959fc2547002a16029adae4bff2c0568928f505954b06369d77/async_stagger-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "7238683f538c91b13e20bd64bff42aec", "sha256": "386a9d0ef5cba1a0cd27cf6b7645e4abd24d8f5a39dde065c7c141ecece07c07" }, "downloads": -1, "filename": "async_stagger-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "7238683f538c91b13e20bd64bff42aec", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 23725, "upload_time": "2018-09-10T07:16:05", "url": "https://files.pythonhosted.org/packages/5e/cf/f1286dfc598322523f597eadce43cbd096cbab35099be4516bb88d07b802/async_stagger-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3fec0b06f727f9d9046eee5d4a37fc2c", "sha256": "bc4c38dbbb83bdb619a89fd729377479c838b5547360af4d59b9a6dc563ba707" }, "downloads": -1, "filename": "async_stagger-0.2.1.tar.gz", "has_sig": false, "md5_digest": "3fec0b06f727f9d9046eee5d4a37fc2c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 18602, "upload_time": "2018-09-10T07:16:06", "url": "https://files.pythonhosted.org/packages/b0/f9/cf8addc7f3e7aaf059cf2ebbb98969def6de9839c957d4045ada8b2289c4/async_stagger-0.2.1.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "4e547070ff62b7a25a7f0150c2cc0e62", "sha256": "c1d814587c14d7b8d7413194d7e31573a6a74fceb9c21750b139daa781321212" }, "downloads": -1, "filename": "async_stagger-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "4e547070ff62b7a25a7f0150c2cc0e62", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 27171, "upload_time": "2018-12-20T15:20:20", "url": "https://files.pythonhosted.org/packages/82/d6/78ed55559161b0ad4801d87a20ff7e91ea36744c8a2542d87e9090d80e4a/async_stagger-0.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9860f9bca1c20b3afa13cd113a893174", "sha256": "1c7817ccb2e85d8179742417b5e7ecbf9e114345e9e3bac7feae89b91c29f400" }, "downloads": -1, "filename": "async_stagger-0.3.0.tar.gz", "has_sig": false, "md5_digest": "9860f9bca1c20b3afa13cd113a893174", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 23207, "upload_time": "2018-12-20T15:20:22", "url": "https://files.pythonhosted.org/packages/d3/8a/e38a29f65f1a28ad0a19f9dfdb084a0fae4ca1be630aa3c34511d219e54c/async_stagger-0.3.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "4e547070ff62b7a25a7f0150c2cc0e62", "sha256": "c1d814587c14d7b8d7413194d7e31573a6a74fceb9c21750b139daa781321212" }, "downloads": -1, "filename": "async_stagger-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "4e547070ff62b7a25a7f0150c2cc0e62", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 27171, "upload_time": "2018-12-20T15:20:20", "url": "https://files.pythonhosted.org/packages/82/d6/78ed55559161b0ad4801d87a20ff7e91ea36744c8a2542d87e9090d80e4a/async_stagger-0.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9860f9bca1c20b3afa13cd113a893174", "sha256": "1c7817ccb2e85d8179742417b5e7ecbf9e114345e9e3bac7feae89b91c29f400" }, "downloads": -1, "filename": "async_stagger-0.3.0.tar.gz", "has_sig": false, "md5_digest": "9860f9bca1c20b3afa13cd113a893174", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 23207, "upload_time": "2018-12-20T15:20:22", "url": "https://files.pythonhosted.org/packages/d3/8a/e38a29f65f1a28ad0a19f9dfdb084a0fae4ca1be630aa3c34511d219e54c/async_stagger-0.3.0.tar.gz" } ] }