-
-
Notifications
You must be signed in to change notification settings - Fork 726
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
Add a trio-based worker. #118
Conversation
Interesting. Note that the protocol class uses asyncio.get_event_loop() and loop.create_task() which I assume aren’t working as expected in this context? |
I guess you could fix that with an adapter that takes the nursery, and exposes a create_task(...) method that actually calls nursery.start_soon(...). Then include this to the protocol class arguments: ‘loop=NuseryAdapter(nursery)’, right? |
The way I am doing this is by implementing the interface of the Protocol and Transport classes: https://github.com/miracle2k/trio-protocol is a dependency. Again, this is all very experimental for now, I just hacked it together in the last 3 hours or so. However, it does serve simple requests! |
FWIW, it does pass in a custom loop object that implements |
Nice! |
I didn’t understand this point. Does trio expose a differing transport interface? |
Both In |
Right. Tho we’re taking care of flow control, and the application only ever sees ‘send’ and ‘receive’ async interfaces, so we don’t really need to be concerned that trio offers a differently designed interface for I/O. (Since apps never see that level of abstraction anyways) One thing I particularly like about ASGI is that it removes the application developer from having to be concerned about the asyncio interface itself - instead you’re just in async/await land. The one point where that doesn’t hold is when applications want to spawn a task. It’s possible that ASGI could mandate a particular async interface for that, in order to provide:
|
At PyCon I discussed this point with Andrew and other framework devs and I think we decided that ASGI should provide some mechanism for the app to request a worker (async or thread executor for sync) from the server. This was not only for background tasks but also so that an app could dispatch both sync and async view functions (it would request an executor if it saw a sync view). I'm probably getting the details wrong, it's been a while. I don't think this is in the spec yet, so it would probably be a good time to open a discussion in the spec repo. |
I might be misunderstanding - my apologies - but it needs to be trio all the way down, right? (or asyncio all the way down). So, if the code that reads http requests from the socket (i.e. the worker) runs in the asyncio main loop, then my app, behind ASGI, needs to use asyncio as well. I cannot call |
Yes. I’m just exploring what interface would need to be provided in order to provide a subset of async functionality, where the application doesn’t care what the underlying async implementation is. Eg if awaitable ‘sleep’ and ‘create_task’ interfaces are passed in on object in the scope then applications could call those, rather than calling ‘asyncio’ or ‘trio’. For a very large slice of stuff ASGI apps shouldn’t need any of the low level APIs exposed by trio/asyncio/curio. (Since that’s all taken care of in the server.) |
Presumably database drivers, redis interfaces, and HTTP client tooling would have to be specific to the async implementation, since they’ll necessarily use low-level async APIs. Other stuff such as middleware or application code might be able to be async-implementation-independent, so long as it followed a style of using an interface explicitly passed to it by the server. (This is all just speculative stuff of course) |
I see. Intriguing idea. There is the https://github.com/theelous3/multio library for prior art that might be of interest. It might all be possible, but I am personally not hopeful it will work out so well in practice. At the end of every
All of these are specific to the framework used, and without them we can't do a lot with async, and it seems quite a burden for the ASGI spec to carry these quite specific things. It would also now require all middleware and application authors to use a new API defined by ASGI (or the web framework implementing ASGI) instead of working directly with trio or asyncio. I fear that in pursuit of making middleware interoperable, we are just adding one more API into the mix. |
There are some things we could do to provide a degree of interoperability tho. Eg provide the ‘loop’ to the scope, and recommend that apps use that explicitly rather than ‘asyncio.get_event_loop’ (which for instance allows trio-protocol to transparently work with ASGI apps that create tasks.) More broadly the question would be: what set of additional constraints that trio or curio have designed for might we also want want to apply to async-within-ASGI. Trio’s nursery constraint can roughly be encapsulated within ASGI if we follow some additional “only create tasks using the loop interface provided in the scope”, as the server is then in a position to monitor the lifetimes of any sub tasks created. |
So I guess if we could modify Obv it'll be less interoperable than other ASGI implementations, but for anything where it's just using the ASGI interface and |
A while ago I started the process of publishing it as a standalone package (https://github.com/miracle2k/trio-asgi-server), but I never got around to finishing that - I also wanted to finish the I'm happy to add it to uvicorn instead, though. |
Nice one. I reckon the best tack is probably to keep this entirely third-party, so let’s close this off. However:
Cheers! 😃 |
@miracle2k On re-review I think I'd be pretty happy to see a trio implementation in the core, tho I'd probably start from the POV of |
This is definitely experimental at this point. Just wanted to show this off, and ask if this is something that makes sense as part of
uvicorn
. It could well be a separate package which imports theuvicorn
protocol classes instead. On the other hand,uvicorn
is currently a small-enough package that I could see it expand it's scope a little bit.