question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Revisiting some thoughts on this following on from #118

I’m not against having trio-support as one of the built-in options. Presumably that’d mean using --loop trio, and having that switch out:

  • The loop implementation.
  • The server class implementation.
  • Using a new trio h11 based protocol implementation for the default --http auto.

The asyncio/trio/curio split is problematic, but it’s an ecosystem issue, rather than an ASGI issue (ASGI is just an async/await interface, and is agnostic what event loop implementation is used to call into that interface.)

The problem is that whatever event loop implementation you’re running in must also match any async primitives used in the application codebase.

If you’re just using async/await and send/receive, then it doesn’t matter, but as soon as you start using things like asyncio.sleep()/trio.sleep(), or creating concurrent tasks, or accessing network or file I/O directly, then you’re locked into whichever system you’re in.

I’d say that Trio is indisputably more refined and more properly constrained than asyncio, but the ecosystem split is problematic.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:7
  • Comments:23 (18 by maintainers)

github_iconTop GitHub Comments

4reactions
florimondmancacommented, Nov 23, 2020

I’ve done more investigation, and from what I found out it seems there may not be a safe, simple way to transition incrementally from the current state to an “async agnostic” state, at least without partial rewrites of lots of stuff.

For example, the “protocols” code (h11 and httptools for HTTP/1.1, wsproto for WebSocket) is very much entangled with asyncio (mostly because of the use of the transport/protocol API, rather than the streams API).

Additive rewrite?

So I’m exploring the space of what’s possible on a branch: https://github.com/encode/uvicorn/tree/fm/async-agnostic

My approach there is to rewrite parts of Uvicorn (basically everything that touches networking, plus the lifespan code) independently of the existing code paths.

The rewritten code uses an AsyncBackend API (approach very similar to what we’ve done in HTTPCore).

The new code path can be taken by passing an --async-library ... flag. This selects the async backend on startup (and we can auto-detect it when inside the server code for our own convenience).

Current status

I’m quite happy to say that I’ve got a lot working on that branch yet:

  • HTTP/1.1 server implementation (no WebSocket yet) for h11 + httptools
  • asyncio + trio + curio 🎉

File structure (approximately):

_async_agnostic/
  # Async backends, similar to approach in HTTPCore. Provides an `AsyncSocket` abstraction, among other things
  backends/

  # HTTP/1.1 implementation
  http11/
    parsers/  # Sans-I/O parsers
      base.py  # Interface (inspired by `h11.Connection`)
      h11.py
      httptools.py
    handler.py  # Handler interface implementation.

  # Server implementation.
  # Relies on a "handler" interface: `async handler(sock, state, config) -> None`
  # This is similar to trio's and curio's server APIs, which expect
  # a `async handler(stream) -> None` function to be passed.
  # This allows preparing support for HTTP/2 (basically: add `http2/`, and a handler).
  # The server is responsible for "things around actually serving connections", such as
  # running the lifespan task, or listening for shutdown signals.
  # (This means handlers are testable in isolation.)
  server.py

The _async_agnostic directory lives within uvicorn/. When --async-library is given, the main run() function targets the new async-agnostic server’s .run(), rather than the existing asyncio-only server. (That one is currently in _impl/asyncio.py, we may want to revert that and move it to _server.py, or similar.)

I also have a tests/async_agnostic directory, with relevant tests copied over and adapted using the new internal async-agnostic APIs. I’m happy to say that all tests pass. ✅

Is this madness?

Well, probably. 😃

Obviously we can’t ever downright replace what’s in Uvicorn right now with what I’m working on in that branch.

Also I’m aware the code I’m working on mixes two problems: async-agnosticity, and preparing for HTTP/2 support. It’s very possible that preparing HTTP/2 support could be done separately. (And an internal “handler API” could be a sensible way to go. It should make it much easier to add HTTP/2 support incrementally, by simply adding an HTTP/2 handler, implemented with h2 for example.)

But as for the async-agnostic side of things, there may be a way forward in the form of a “new implementation” that exists alongside the existing one, and that users are able to opt into (using --async-library (asyncio|trio|curio)).

If we think this is an interesting path forward, we could go for something like this:

  1. Add new implementation, as a “opt-in beta”. This can be released in a minor release, since it’s purely additive.
  2. Let new implementation live on for a while. Add more to it (eg WebSocket support, which I think is the only thing missing in my branch).
  3. Once the new implementation seems ready enough, exit the “live beta” phase. Deprecate the older implementation, eg by marking the absence of --async-library deprecated.
  4. Make the switch by making the new implementation opt-out.

There are pain points, though:

  • We’ll need to maintain two implementations. They look different, which may make back-porting bug fixes from one to the other non-trivial (not just copy pasting).
  • Introduces a bit of a burden on users — at least, we need to make sure the communication is efficient.

But…

  • The “live beta” phase is safe for users: no risk of breaking changes, since it’s purely additive, and always opt-in.

Happy to read thoughts about this! I keep working on my branch since I think it’s a valuable bunch of work anyway (I’ve already cumulatively spent a few days straight on it!), at least for figuring out what can be done and how.

(Also interesting to think about this wrt HTTPCore: I think we have a “someday” ambition to build a server-side minimal HTTP server implementation, compatible with sync/async, with support for various async libraries, various parsers, etc…)

2reactions
florimondmancacommented, Aug 15, 2021

to use anyio async functions.

@graingert Let’s remember from past discussions that we want to keep a fast-track code path for asyncio, as Uvicorn is also meant to be a flagship for a fast and lightweight async server. This means keeping the existing asyncio-optimized code, and so I don’t think we should make anyio required like we did in Starlette (where I think we could have done without anyio magic too for the sake of future maintenance, but I didn’t participate in that decision).

I had also laid out ways we could move forward without anyio for trio support. I’d understand the motivation for using that as a first step for trio support, but this is just a note that I hope it is clear that we really do want to keep the existing asyncio code in place.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Federal TRIO Programs - Home Page - Department of Education
The Federal TRIO Programs are educational opportunity outreach programs designed to motivate and support students from disadvantaged ...
Read more >
TRIO - Benefits.gov
You need to enable JavaScript to run this app.
Read more >
TRIO Student Support Services - CNM
TRIO Student Support Services provides assistance to qualifying students who plan to graduate from CNM and then transfer to a four-year institution.
Read more >
TRIO Student Support Services - University of Louisville
TRIO Student Support Services (SSS) is funded by the U.S. Department of Education and the University of Louisville. SSS is committed to helping...
Read more >
TRIO Support Services Program
TRIO Student Support Services (SSS) is located in The Academic Support Center in the Student Services building, room 159. TRIO is funded by...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found