-
-
Notifications
You must be signed in to change notification settings - Fork 183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support pluggable http clients/coroutine frameworks (anyio/httpx) #749
Comments
As far as I'm aware aiobotocore would need to replace all asyncio calls with the relevant anyio equivalent, and any gather/ensure_future with a nursary/spawn pattern instead |
should be done with #619 which will cause a TON of refactoring and perhaps re-thinking this whole project |
I don't think #619 and this issue are really that coupled and could be completed in any order |
botocore/boto3 already supports an event callback for extensions and aiobotocore inherits that behavior without any modifications. See
To focus only on the All of this is easily understood (mostly) from reading |
the reason I said #619 (#659) is because it's going to greatly expand this codebase, and thus parts which would need to be refactored to support whats mentioned in this issue. IIRC there are sleeps/locks for example in the new credentials file we need to replace components in. @dazza-codes that's great insight for that one particular event, I just logged #774 so we don't forget about it and apply it where possible. Given #659 moves us to async events a lot more will be possible. |
What is the roadmap here. I would contribute if there's a plan.
|
@toidi step 1 would be to find any imports/calls to asyncio and replace it with the anyio equivalent |
@thehesiod are you ok with the proposal above? |
Let me take a look at anyio and report back |
ok looking at anyio that's not going to solve the http client portion, that tries to solve asyncio event loop plugging, which actually is already designed to be globally replaceable (see for example how uvloop works). From what I can see botocore is already working on a pluggable http client session, see: https://github.com/boto/botocore/blob/develop/botocore/endpoint.py#L280 however it's not piped to either Config or create_client yet from what I can see, seems like a WIP. So I think we need to wait to see what botocore is going to do. Another factor is that it's not as simple as just allowing a aiohttp replacement, you need to port all the exceptions as well (https://github.com/aio-libs/aiobotocore/blob/master/aiobotocore/endpoint.py#L156), I just went through that in fact on the most recent botocore update. looping in @terrycain . |
I'm looking to replace the coroutine framework not the event loop |
ah I c, sorry this is a two prong request, probably should be split as they're not necessarily related |
Well it's mainly about the pluggable coroutine framework, as I'd like to be able to use aiobotocore on curio and trio applications. For this to happen asyncio and aiohttp both need replacing as they both only support asyncio event loops |
So, theres 2 pieces of work here. Making the event loop more customisable than just the asyncio backend implementation so we can use things like trio and curio. As well as making the http client swappable as aiohttp does not work with curio/trio. Both bits of work are required before any of this work is really usable. In terms of swapping asyncio invocations to anyio, from a glance I don't see that causing any issues, it would be nice to see if there is any performance degradation with the switch, though it should just be a wrapper to the asyncio function call. |
the changes to aiobotocore for anyio will be quite minimal:
and I think we'd need a |
the TimeoutErrors would have to be handled a bit more carefully as modern coroutine frameworks discourage "libraries from using internal timeouts. Instead, it encourages the caller to enforce timeouts, which makes timeout code easier to compose and reason about." so this code: aiobotocore/aiobotocore/utils.py Lines 44 to 72 in 3faf885
would use async def _fetch_metadata_token(self):
self._assert_enabled()
url = self._base_url + self._TOKEN_PATH
headers = {
'x-aws-ec2-metadata-token-ttl-seconds': self._TOKEN_TTL,
}
self._add_user_agent(headers)
request = botocore.awsrequest.AWSRequest(
method='PUT', url=url, headers=headers)
async with self._session(timeout=None,
trust_env=self._trust_env) as session:
for i in range(self._num_attempts):
with anyio.move_on_after(timeout):
try:
async with session.put(url, headers=headers) as resp:
text = await resp.text()
if resp.status == 200:
return text
if resp.status in (404, 403, 405):
return None
if resp.status in (400,):
raise BadIMDSRequestError(request)
except RETRYABLE_HTTP_ERRORS as e:
logger.debug(
"Caught retryable HTTP exception while making metadata "
"service request to %s: %s", url, e, exc_info=True)
except aiohttp.client_exceptions.ClientConnectorError as e:
if getattr(e, 'errno', None) == 8 or \
str(getattr(e, 'os_error', None)) == \
'Domain name not found': # threaded vs async resolver
raise InvalidIMDSEndpointError(endpoint=url, error=e)
raise
return None |
the similar discussion in HTTPX if aiobotocore would go for pluggable HTTP client - coroutine framework is not a requirement |
@toidi httpx uses its own abstraction https://github.com/encode/httpcore/blob/master/httpcore/_backends/anyio.py which is for opening sockets, creating locks and sleeping. aiobotocore also needs subprocess support |
@emcpow2 httpx and encode in general have fully bought into anyio now: https://github.com/encode/httpcore/blob/f0d16e9462910c13d3b72039223346a3fe8a3299/CHANGELOG.md#fixed-2 |
I'm also really keen to use aiobotocore with Trio - and it looks like there's a reasonable two-step process:
The best way forward is probably for someone to draft a PR for (1), and then we can decide whether it's easier to do the two parts together or separately. |
yea, we've been internally switching to httpx for some of jobs because aiohttp keeps giving random https payload errors. I'm all for this now |
it's easier now with the refactoring botocore has done and we've incorporated |
After working on implementing httpx this is likely going to cause quite a few changes in user code, and some functionality would be straight up lost due to httpx not having the exact same feature set as aiohttp - e.g. encode/httpx#2211 In general the code feels quite tightly coupled to aiohttp, such that it would look very different if it'd been written for httpx from the start, and even where it would be possible in theory to create a seamless transition for end users it'd lead to very clunky code. E.g. I'm starting to want to completely drop So I'm starting to lean towards it being easiest initially to implement httpx alongside aiohttp, and you can specify which one to use upon initialization of the session. This way I don't have to initially bother with full support for niche stuff like proxies, ssl certificates, etc etc (which in several cases doesn't even seem to have tests, which makes it very hard for me to guarantee functionality isn't changed) and can much more easily break it up into multiple PRs. And then when the |
This issue has been marked as stale because it has been inactive for more than 60 days. Please update this pull request or it will be automatically closed in 7 days. |
This likely shouldn't be closed as not planned unless we're dropping #1085 |
I'd like to be able to use aiobotocore in a project that uses trio and httpx
anyio provides a generic interface to curio/trio/asyncio that libraries can use to provide generic support for all async/await eventloops
aiobotocore would require users to pass a "request" coroutine function that provides all the http functionality that aiobotocore needs for http requests
The text was updated successfully, but these errors were encountered: