-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
This issue isn't neccessarily something that I think we ought to do, or not do. However, since we've got our public API pretty squared away now, and are starting to think about a 1.0 release, it's something that we really ought to discuss, and make sure we're absolutely happy with whatever we land on.
Something that's come up as a possible? point of design contention has been if AsyncClient ought to strictly only provide a context-managed interface, or if we're okay with supporting __init__ and, optionally calling .aclose().
Currently we're supporting either style, and that's working fine for our users, but...
- If we ever wanted to support background tasks, then structured concurrency means we'd want the client instances to be context-managed, so that we've got well defined lifetimes for any background running tasks.
- The context managed style also means strictly managed resource managment. Connections have well-scoped lifetimes, rather than "cleanup on interpreter exit".
Do we need to be able to support background tasks. Well, possibly.
We don't strictly need background tasks to support our HTTP/2 implementation, so long as we're using HTTP/1.1 shortish timeouts, on connections that have no activity. (If we're not running a background task on it, then if there's no request/response activity progressing the connection, then we won't respond to HTTP/2 pings, and servers will time us out.)
However, if we did have background tasks then...
- We could have nicer HTTP/1.1 keep-alive timeouts, where we actually properly expire connections in the background after their timeout period.
- We could optionally support long-lived HTTP/2 connections, holding onto a connection for longer periods of time in order to provide lower latency when the next request is made.
Also, I've no idea how this ties in with HTTP/3.
Other relevant factors here:
- It's also possible that some limited kinds of global tasks might at some point be supported by
trio[discussion] [potential heresy] global connection pools and global tasks python-trio/hip#125 - One reason I was initially reticant about strictly enforcing context managed async clients is that I wasn't clear how that'd fit in with the ASGI style, but having put some more thought in there it's clear that it can fit in with ASGI's lifespan messaging. Eg: Support generator function to manage startup/shutdown. Kludex/starlette#799
- We'd be suggesting a deliberate disparity with the sync case, which is a bit odd. I don't think we'd want to / be able to enforce context managed sync clients. It wouldn't work with WSGI, and anyways we'd like folks to be able to switch over from using
requeststo usinghttpx, and we wouldn't be able to justify the constraint. It's also less valuable since we wouldn't be running background tasks in the sync case anyways, so it'd only be relevant wrt. clean connection lifetimes. - Simply having an async context managed class doesn't actually tie in fully with "And we'd like a nursery available within this context" See conversation around https://gitter.im/python-trio/general?at=5e20aa33ad195a0f671cc071 - You can do it with some clever metaclassing, or you can potnentially call directly into the nursery
__aenter__and__aexit__, but it might not neccessarily? be the API we'd want to adopt if we wanted a nusery available withinAsyncClient. (I think we'd probably? on ok ground here tho' - there's options available.)
I don't have any clear answer on this. What we've got at the moment is working fine for our users, but it's feasible that adopting the more constrained option could prevent issues further down the line?