[Web-SIG] Server-side async API implementation sketches
Alice Bevan–McGregor
alice at gothcandy.com
Mon Jan 10 01:39:03 CET 2011
On 2011-01-09 09:26:19 -0800, P.J. Eby said:
> By the way, I don't really see the point of the new sketches you're doing...
I'm sorry.
> ...as they aren't nearly as general as the one I've already done, but
> still have the same fundamental limitation: wsgi.input.
You missed the point entirely, then.
> If wsgi.input offers any synchronous methods...
Regardless of whether or not wsgi.input is implemented in an async way,
wrap it in a future and eventually get around to yielding it. Problem
/solved/. Identical APIs for both sync and async, and if you have an
async server but haven't gotten around to implementing your own
executor yet, wrapping the blocking read call in a future also solves
the problem (albeit not in the most efficient way).
I.e. wrap every call to a wsgi.input method by passing it to wsgi.submit.
> ...then they must be used from a future and must some how raise an
> error when called from within the application -- otherwise it would
> block, nullifying the point ofhaving a generator-based API.
See above. No extra errors, nothing really that insane.
> If it offers only asynchronous methods, OTOH, then you can't pass
> wsgi.input to any existing libraries (e.g. the cgi module).
Describe to me how a function can be suspended (other than magical
greenthreads) if it does not yield; if I knew this, maybe I wouldn't be
so confused.
> The latter problem is the worse one, because it means that the
> translation of an app between my original WSGI2 API and the current
> sketch is no longer just "replace 'return' with 'yield'".
I've deviated from your sketch, obviously, and any semblance of
yielding a 3-tuple. Stop thinking of my example code as conforming to
your ideas; it's a new idea, or, worst case, a narrowing of an idea
into its simplest form.
> The only way this would work is if WSGI applications are still allowed
> to be written in a blocking style. Greenlet-based frameworks would
> have no problem with this, of course, but servers like Twisted would
> still have to run WSGI apps in a worker thread pool, just because they
> *might* block.
Then that is not acceptable and "would not work". The mechanics of
yielding futures instances allows you to (in your server) implement the
necessary async code however you wish while providing a uniform
interface to both sync and async applications running on sync and async
servers. In fact, you would be able to safely run a sync application
on an async server and vice-versa. You can, on an async server:
:: Add a callback to the yielded future to re-schedule the application
generator.
:: If using greenthreads, just block on future.result() then
immediately wake up the application generator.
:: Do other things I can't think of because I'm still waking up.
The first solution is how Marrow HTTPd would operate.
> If we're okay with this as a limitation, then adding _async method
> variants that return futures might work, and we can proceed from there.
That is not optimum, because now you have an optional API that
applications who want to be compatible will need to detect and choose
between.
> Mostly, though, it seems to me that the need to be able to write
> blocking code does away with most of the benefit of trying to have a
> single API in the first place.
You have artificially created this need, ignoring the semantics of
using the server-specific executor to detect async-capable requests and
the yield mechanics I suggested; which happens to be a single, coherent
API across sync and async servers and applications.
- Alice.
More information about the Web-SIG
mailing list