[Web-SIG] Server-side async API implementation sketches

P.J. Eby pje at telecommunity.com
Mon Jan 10 15:43:54 CET 2011


At 04:39 PM 1/9/2011 -0800, Alice Bevan­McGregor wrote:
>On 2011-01-09 09:26:19 -0800, P.J. Eby said:
>>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/.

Not the API problem.  If I'm accustomed to writing synchronous code, 
the async version looks ridiculous.  Also, an existing WSGI web 
framework isn't going to be able to be ported to this API without 
putting it in a future.

My hope was for an API that would be a simple enough translation that 
*everybody* could be persuaded to use it, but having to use futures 
just to write a "normal" application simply isn't going to work for 
the core WSGI API.  As a separate "WSGI-A" profile, sure, it works fine.


>>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.

I'm not sure what you're confused about.  I'm the one who forgot you 
have to read from wsgi.input in a blocking way to write a normal app.  ;-)

(Mainly, because I was so excited about the potential in your 
sketched API, and I got sucked into the process of implementing/improving it.)


>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.

What I'm trying to point out is that you've missed two important API 
enhancements in my sketch, that make it so that app and middleware 
authors don't have to explicitly manage any generator methods or even 
future methods.


>  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.

I am not sure why you're reiterating these things.  The sample code I 
posted shows precisely where you'd *do* them in a sync or async 
server.  That's not where the problem lies.


>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.

It wasn't supposed to be optional, but it's beside the point since 
the presence of a blocking API means the application can block.

The issue might be addressable by having an environment key like, 
'wsgi.canblock' (indicating whether the application is already in a 
separate thread/process), and a piece of middleware that simply 
spawns its child app to a future if wsgi.canblock isn't set.  Then 
people who write blocking applications could use the decorator.



>>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.

I haven't ignored them.  I'm simply representing the POV of existing 
WSGI apps and frameworks, which currently block, and are unlikely to 
be rewritten so as not to block.  I thought, briefly, that it was 
possible to make an API with a low-enough conceptual overhead to 
allow that porting to occur, and let my enthusiasm carry me away.

I was wrong, though: even the extremely minimalist version isn't 
going to be usable for ported code, which relegates the async version 
to a niche role.

I would note, though, that this is *still* better than my previous 
position, which was that there was no point making an async API *at all*.  ;-)



More information about the Web-SIG mailing list