<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">I described a different way of doing WSGI which would better cope with post response hooks at the Python Web Summit at PyCon in 2012. It made use of the context manager abstraction so it wouldn't screw with the returned iterable.<div><br></div><div><a href="http://www.slideshare.net/GrahamDumpleton/pycon-us-2012-state-of-wsgi-2-14808297">http://www.slideshare.net/GrahamDumpleton/pycon-us-2012-state-of-wsgi-2-14808297</a></div><div><br></div><div>Graham</div><div><div><br><div><div>On 27/04/2013, at 2:36 PM, est <<a href="mailto:electronixtar@gmail.com">electronixtar@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div dir="ltr">Hi,<div><br></div><div style="">Newbie opinion here.</div><div style=""><br></div><div style="">Since we are talking about Tulip and PEP 3156, I think it's high time we address some of the design flaws in WSGI 1.0</div>

<div style=""><br></div><div style="">One major problem with WSGI is that it can not handle true post-response hooks.</div><div style=""><br></div><div style="">The closest hack I found is this:</div><div style=""><a href="https://modwsgi.readthedocs.org/en/latest/developer-guides/registering-cleanup-code.html">https://modwsgi.readthedocs.org/en/latest/developer-guides/registering-cleanup-code.html</a><br>

</div><div style=""><br></div><div style=""><br></div><div style=""><div>As discussed by Graham Dumpleton here</div><div><a href="https://groups.google.com/group/modwsgi/msg/d699a09b3b11b313">https://groups.google.com/group/modwsgi/msg/d699a09b3b11b313</a></div>

<div><br></div><div style="">Although the response was returned to the client, It will still hold the http connection open until __callback finishes.</div></div><div style=""><br></div><div style="">While it's pretty common design pattern for a post-response hook in modern Web world. I can think a few usage:</div>

<div style=""><br></div><div style=""> - User uploads file, return HTML says Upload OK, then Web worker continue to transfer file to Amazon S3, which is slow and takes some time.</div><div style=""> - After a series of user interaction on a web page, using the existing db connection to write OLAP logs of later analysis.</div>

<div style=""> - notify the http request to another ZMQ/XMPP connection</div><div style=""><br></div><div style="">Currently, Celery is extremely popular (at least in Django or other non-async web frameworks). But IMHO it's too heavy weight and copying python data & objects from a cluster of Web workers to another cluster of task queue workers is not worth it.</div>

<div style=""><br></div><div style="">Another problem is the good old CGI environ design. I can't help to ask? Why?</div><div style=""><br></div><div style="">Every HTTP header is transfered via envion, and capitalized with a HTTP_ prefix e.g. HTTP_HOST. There's some serious information loss here.</div>

<div style=""><br></div><div style="">1. Actual header string case </div><div style="">2. header order</div><div style=""><br></div><div style="">Since WSGI is higher level framework, I think it's time for us to deliver the original header status in a SortedDict.</div>

<div style=""><br></div><div style="">Again, as a newbie advice, we should take this chance of integrating PEP 3156 with a deadly simple WSGI 3.0 design:</div><div style=""><br></div><div style="">def application(request):</div><div style="">

    ip = request.remote_ip</div><div style="">    length = request.headers["Content-Length"]</div><div style="">    request.write("<html>done.</html>")</div><div style="">    request.close()</div><div style="">

    db.log(length) # some post-response actions.</div><div style=""><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Mar 25, 2013 at 9:08 AM, Guido van Rossum <span dir="ltr"><<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div>Hi Luca,<br><br></div>Unfortunately I haven't thought yet about the interactions between WSGI and Tulip or PEP 3156. While I am pretty familiar with WSGI, I have never used its async features, so I can't be much of a help. My best guess is that we won't make any changes to WSGI to support PEP 3156 in Python 3.4, but that once that is out, some folks will come up with an improved design for WSGI that supports interoperability with standard async event loops. OTOH, maybe you can read up on the PEP and check out the Tulip implementation (<a href="http://code.google.com/p/tulip/" target="_blank">http://code.google.com/p/tulip/</a>) and maybe you can come up with a suitable design for integrating PEP 3156 into WSGI? Though it may have to be named WSGI 2.0 to emphasize that it is backwards incompatible.<br>



<br></div>--Guido<br><br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Mar 24, 2013 at 2:18 PM, Luca Sbardella <span dir="ltr"><<a href="mailto:luca.sbardella@gmail.com" target="_blank">luca.sbardella@gmail.com</a>></span> wrote:<br>



<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hello,<div><br></div><div>first time here, I'm Luca and I write lots of python of the asynchronous variety.</div>



<div>This question is about wsgi and the way pulsar <a href="http://quantmind.github.com/pulsar/" target="_blank">http://quantmind.github.com/pulsar/</a> handles asynchronous wsgi responses.</div>
<div><br></div><div>Yesterday I sent a message to the python-dev mailing list regarding wsgiref.validator, this is the original message</div><div><br></div><div><div><div><font face="Arial, Verdana, Geneva, Bitstream Vera Sans, Helvetica, sans-serif"><span style="font-size:15px;line-height:21px">I have an asynchronous wsgi application handler which yields empty bytes before it is ready to yield the response body and, importantly, to call start_response.</span></font></div>




<div><font face="Arial, Verdana, Geneva, Bitstream Vera Sans, Helvetica, sans-serif"><span style="font-size:15px;line-height:21px"><br></span></font></div><div><font face="Arial, Verdana, Geneva, Bitstream Vera Sans, Helvetica, sans-serif"><span style="font-size:15px;line-height:21px">Something like this:</span></font></div>




</div><div><div><font face="Arial, Verdana, Geneva, Bitstream Vera Sans, Helvetica, sans-serif"><span style="font-size:15px;line-height:21px"><div><br></div><div>def wsgi_handler(environ, start_response):</div>



<div>        body = generate_body(environ)</div>
</span></font></div><font face="Arial, Verdana, Geneva, Bitstream Vera Sans, Helvetica, sans-serif"><div><div style="font-size:15px;line-height:21px">        body = maybe_async(body)</div><div style="font-size:15px;line-height:21px">




        while is_async(body):</div><div style="font-size:15px;line-height:21px">            yield b''</div><div style="font-size:15px;line-height:21px">        start_response(...)</div><div style="font-size:15px;line-height:21px">




        ...</div><div style="font-size:15px;line-height:21px"><br></div><div style="font-size:15px;line-height:21px">I started using wsgiref.validator recently, nice little gem in the standard lib, and I discovered that the above handler does not validate! Disaster.</div>




<div style="font-size:15px;line-height:21px">Reading pep 3333</div><div style="font-size:15px;line-height:21px"> </div><div style="font-size:15px;line-height:21px">"the application <strong>must</strong> invoke the <tt style="line-height:normal">start_response()</tt> callable before the iterable yields its first body bytestring, so that the server can send the headers before any body content. However, this invocation <strong>may</strong> be performed by the iterable's first iteration, so servers <strong>must not</strong> assume that <tt style="line-height:normal">start_response()</tt> has been called before they begin iterating over the iterable."</div>




<div style="font-size:15px;line-height:21px"><br></div></div><div><div style="font-size:15px;line-height:21px">The pseudocode above does yields bytes before start_response, but they are not *body* bytes, they are empty bytes so that the asynchronous wsgi server releases the eventloop and call back at the next eventloop iteration.</div>




<div><br></div></div></font></div></div><div><br></div><div>And the response was</div><div class="im"><div class="gmail_extra"><br><br><div class="gmail_quote"><span dir="ltr"></span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">





<div>>PJ Eby wrote:<br>
>> The validator is correct for the spec.  You *must* call<br>
>> start_response() before yielding any strings at all.<br>
><br>
><br>
> Thanks for response PJ,<br>
> that is what I, unfortunately, didn't want to hear, the validator being<br>
> correct for the "spec" means I can't use it for my asynchronous stuff, which<br>
> is a shame :-(((<br>
> But why commit to send headers when you may not know about your response?<br>
> Sorry if this is the wrong mailing list for the issue, I'll adjust as I go<br>
> along.<br>
<br>
</div>Because async was added as an afterthought to WSGI about nine years<br>
ago, and we didn't get it right, but it long ago was too late to do<br>
anything about it.  A properly async WSGI implementation will probably<br>
have to wait for Tulip (Guido's project to bring a standard async<br>
programming API to Python).<br>
</blockquote></div><br></div></div><div class="gmail_extra">and so here I am.</div><div class="gmail_extra">I know tulip is on its early stages but is there anything on the pipeline about wsgi?</div><div class="gmail_extra">




Happy to help if needed.</div><div class="gmail_extra"><br></div><div class="gmail_extra">Regards</div><span><font color="#888888"><div class="gmail_extra">Luca</div><div class="gmail_extra"><br></div></font></span></div>

<span class="HOEnZb"><font color="#888888">


</font></span></blockquote></div><span class="HOEnZb"><font color="#888888"><br><br clear="all"><br>-- <br>--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)
</font></span></div>
<br>_______________________________________________<br>
Web-SIG mailing list<br>
<a href="mailto:Web-SIG@python.org">Web-SIG@python.org</a><br>
Web SIG: <a href="http://www.python.org/sigs/web-sig" target="_blank">http://www.python.org/sigs/web-sig</a><br>
Unsubscribe: <a href="http://mail.python.org/mailman/options/web-sig/electronixtar%40gmail.com" target="_blank">http://mail.python.org/mailman/options/web-sig/electronixtar%40gmail.com</a><br>
<br></blockquote></div><br></div>
_______________________________________________<br>Web-SIG mailing list<br><a href="mailto:Web-SIG@python.org">Web-SIG@python.org</a><br>Web SIG: http://www.python.org/sigs/web-sig<br>Unsubscribe: http://mail.python.org/mailman/options/web-sig/graham.dumpleton%40gmail.com<br></blockquote></div><br></div></div></body></html>