[ANN] twsgi: asynchronous WSGI implementation for Twisted Web

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

[ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Manlio Perillo-3
I have started to write an asynchronous WSGI implementation for Twisted Web.

The standard implementation execute the WSGI application in a separate
thread.
twsgi will instead execute the application in the main Twisted thread.

The advantage is that twsgi is better integrated in Twisted, and WSGI
applications will be able to use all features available in Twisted.


Code is availale from a Mercurial repository:
http://hg.mperillo.ath.cx/twisted/twsgi


The purpose of twsgi is to have a pure Python implementation of WSGI
with support for asynchronous HTTP servers and asynchronous WSGI
applications.

The implementation is similar to ngx_http_wsgi_module, and can be used
to quick test asynchronous extensions.

write callable is not implemented (calling it will raise NotImplemented
error), since write callable can not be implemented in an asynchronous
web server without using threads (and twsgi *does* not use threads).

ngx_http_wsgi_module does the same.


TODO
----

* support for suspending iteration over WSGI app iter, when socket is
  not ready to send data.
  execution will be resumed when socked is ready again.

* support for suspend/resume extension, as described here:
  http://comments.gmane.org/gmane.comp.python.twisted.web/632

  It will have some differences:

    - the name will be 'wsgiorg.suspend' instead of 'wsgi.pause_output'

      The wsgiorg namespace is used, since the plan is to have it
      standardized [1], but it can only be implemented on asynchronous
      servers.

    - wsgi.pause_output function will accept an optional timeout, in
      milliseconds.

      If timeout is specified, application will be implicitly resumed
      when timeout expires.

    - resume function will return a boolean value.
      True: if execution was suspended and it is going to be resumed
      False: if execution was not suspended

      The return value can be used to check if timeout specified in
      wsgiorg.suspend expired.

      I'm not sure if a boolean value is the best solution.
      Maybe it should return -1 is execution was not suspended, and 0
      otherwise.


[1] unlike other proposed async extensions, suspend/resume is much more
    simple and easy to implement, so it is more likely to have a wide
    consensus over the specification.


Feedbacks are welcomed.


Regards  Manlio
_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Graham Dumpleton-2
On 9 April 2010 21:00, Manlio Perillo <[hidden email]> wrote:

> I have started to write an asynchronous WSGI implementation for Twisted Web.
>
> The standard implementation execute the WSGI application in a separate
> thread.
> twsgi will instead execute the application in the main Twisted thread.
>
> The advantage is that twsgi is better integrated in Twisted, and WSGI
> applications will be able to use all features available in Twisted.
>
>
> Code is availale from a Mercurial repository:
> http://hg.mperillo.ath.cx/twisted/twsgi
>
>
> The purpose of twsgi is to have a pure Python implementation of WSGI
> with support for asynchronous HTTP servers and asynchronous WSGI
> applications.
>
> The implementation is similar to ngx_http_wsgi_module, and can be used
> to quick test asynchronous extensions.
>
> write callable is not implemented (calling it will raise NotImplemented
> error), since write callable can not be implemented in an asynchronous
> web server without using threads (and twsgi *does* not use threads).
>
> ngx_http_wsgi_module does the same.
>
>
> TODO
> ----
>
> * support for suspending iteration over WSGI app iter, when socket is
>  not ready to send data.
>  execution will be resumed when socked is ready again.
>
> * support for suspend/resume extension, as described here:
>  http://comments.gmane.org/gmane.comp.python.twisted.web/632
>
>  It will have some differences:
>
>    - the name will be 'wsgiorg.suspend' instead of 'wsgi.pause_output'
>
>      The wsgiorg namespace is used, since the plan is to have it
>      standardized [1], but it can only be implemented on asynchronous
>      servers.

Please read:

  http://www.wsgi.org/wsgi/Specifications

If a proposal is suggested, it MUST use 'x-wsgiorg.' and not
'wsgiorg.'. Only after it is officially accepted can it use the
'wsgiorg.'.

I would question whether you should even be using 'x-wsgiorg.' as as
far as I can see from my quick scans of emails, you aren't even
supporting WSGI proper as you are dropping support for bits. As such,
it isn't WSGI, only WSGIish so how can you justify using the name.

Why don't you given it all a completely different name else you will
just cause ongoing confusion like you did with when you felt you could
reuse the 'mod_wsgi' name for your nginx version even though I asked
you to use a different name. It has been an absolute pain seeing
discussions on places like #django irc where people don't know when
people mention mod_wsgi whether they are talking about Apache of
nginx.

Graham

>    - wsgi.pause_output function will accept an optional timeout, in
>      milliseconds.
>
>      If timeout is specified, application will be implicitly resumed
>      when timeout expires.
>
>    - resume function will return a boolean value.
>      True: if execution was suspended and it is going to be resumed
>      False: if execution was not suspended
>
>      The return value can be used to check if timeout specified in
>      wsgiorg.suspend expired.
>
>      I'm not sure if a boolean value is the best solution.
>      Maybe it should return -1 is execution was not suspended, and 0
>      otherwise.
>
>
> [1] unlike other proposed async extensions, suspend/resume is much more
>    simple and easy to implement, so it is more likely to have a wide
>    consensus over the specification.
>
>
> Feedbacks are welcomed.
>
>
> Regards  Manlio
> _______________________________________________
> Web-SIG mailing list
> [hidden email]
> Web SIG: http://www.python.org/sigs/web-sig
> Unsubscribe: http://mail.python.org/mailman/options/web-sig/graham.dumpleton%40gmail.com
>
_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Manlio Perillo-3
Graham Dumpleton ha scritto:

> [...]
>>    - the name will be 'wsgiorg.suspend' instead of 'wsgi.pause_output'
>>
>>      The wsgiorg namespace is used, since the plan is to have it
>>      standardized [1], but it can only be implemented on asynchronous
>>      servers.
>
> Please read:
>
>   http://www.wsgi.org/wsgi/Specifications
>
> If a proposal is suggested, it MUST use 'x-wsgiorg.' and not
> 'wsgiorg.'. Only after it is officially accepted can it use the
> 'wsgiorg.'.
>

Well; since the original propose was using wsgi namespace, I just
suggested the use of wsgiorg namespace instead

Of course, when it will be implemented I will use a different namespace,
until it gots approved.

> I would question whether you should even be using 'x-wsgiorg.' as as
> far as I can see from my quick scans of emails, you aren't even
> supporting WSGI proper as you are dropping support for bits. As such,
> it isn't WSGI, only WSGIish so how can you justify using the name.
>

This is not completely correct.
The twsgi implementation, as well ngx_http_wsgi_module implementation,
does not implement the write callable.

The reason is simple: write callable was an huge mistake in WSGI 1.0
since it can not be implemented in an asynchronous web server.

But since the write callable **can** be implemented in a middleware
(using greenlets) and since middlewares *can* be configured inside WSGI
gateway, implementations can still claim to be WSGI 1.0 conformant.

> Why don't you given it all a completely different name else you will
> just cause ongoing confusion

In don't really see how this can cause confusion!

> like you did with when you felt you could
> reuse the 'mod_wsgi' name for your nginx

In fact the first thing I did during code refactoring was to rename it
to ngx_http_wsgi_module.

> version even though I asked
> you to use a different name. It has been an absolute pain seeing
> discussions on places like #django irc where people don't know when
> people mention mod_wsgi whether they are talking about Apache of
> nginx.
>

Apologies for having underestimated this.


Manlio
_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Graham Dumpleton-2
On 9 April 2010 21:29, Manlio Perillo <[hidden email]> wrote:

> Graham Dumpleton ha scritto:
>> [...]
>>>    - the name will be 'wsgiorg.suspend' instead of 'wsgi.pause_output'
>>>
>>>      The wsgiorg namespace is used, since the plan is to have it
>>>      standardized [1], but it can only be implemented on asynchronous
>>>      servers.
>>
>> Please read:
>>
>>   http://www.wsgi.org/wsgi/Specifications
>>
>> If a proposal is suggested, it MUST use 'x-wsgiorg.' and not
>> 'wsgiorg.'. Only after it is officially accepted can it use the
>> 'wsgiorg.'.
>>
>
> Well; since the original propose was using wsgi namespace, I just
> suggested the use of wsgiorg namespace instead
>
> Of course, when it will be implemented I will use a different namespace,
> until it gots approved.
>
>> I would question whether you should even be using 'x-wsgiorg.' as as
>> far as I can see from my quick scans of emails, you aren't even
>> supporting WSGI proper as you are dropping support for bits. As such,
>> it isn't WSGI, only WSGIish so how can you justify using the name.
>>
>
> This is not completely correct.
> The twsgi implementation, as well ngx_http_wsgi_module implementation,
> does not implement the write callable.

So, they aren't compliant with WSGI specification. How is my statement
not correct? If not compliant, how can you use WSGI in their names?

> The reason is simple: write callable was an huge mistake in WSGI 1.0
> since it can not be implemented in an asynchronous web server.

It may not be the preferred way of doing things now, but it was not a
huge mistake. There was a lot of stuff back then that used a write()
style semantic for returning response content and that was the only
way of supporting them without forcing those packages to do a major
rewrite to change to an iterable type response. So, it served its
purpose.

> But since the write callable **can** be implemented in a middleware
> (using greenlets) and since middlewares *can* be configured inside WSGI
> gateway, implementations can still claim to be WSGI 1.0 conformant.

Then only the higher level middleware adapter can even claim to be
WSGI compliant and deserve to use the WSGI name. Any underlying
abstraction you use at the web server interface isn't WSGI and by
rights should be called something else so there is no confusion and
also shouldn't use 'wsgi' keys in its environ dictionary. Have your
high level middleware do a completely remapping of names as
appropriate.

>> Why don't you given it all a completely different name else you will
>> just cause ongoing confusion
>
> In don't really see how this can cause confusion!

So, when someone goes and runs a WSGI application directly against you
WSGIish web server interface which you still insist you can describe
as being WSGI and it fails because the write() method isn't
implemented what is your answr going to be? If something is going to
use WSGI name it should implement the full WSGI specification.

>> like you did with when you felt you could
>> reuse the 'mod_wsgi' name for your nginx
>
> In fact the first thing I did during code refactoring was to rename it
> to ngx_http_wsgi_module.

The mod_wsgi name is still used all through
http://wiki.nginx.org/NginxNgxWSGIModule that I can tell.

Graham
_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Manlio Perillo-3
Graham Dumpleton ha scritto:
> [...]
>> But since the write callable **can** be implemented in a middleware
>> (using greenlets) and since middlewares *can* be configured inside WSGI
>> gateway, implementations can still claim to be WSGI 1.0 conformant.
>
> Then only the higher level middleware adapter can even claim to be
> WSGI compliant and deserve to use the WSGI name.

Since the middleware is executed inside WSGI gateway, and the gateway
can be configured to always execute some middleware, the final
application will simply have at disposal a WSGI conformant write callable.

> Any underlying
> abstraction you use at the web server interface isn't WSGI and by
> rights should be called something else so there is no confusion and
> also shouldn't use 'wsgi' keys in its environ dictionary. Have your
> high level middleware do a completely remapping of names as
> appropriate.
>

This will add useless overhead.

>>> Why don't you given it all a completely different name else you will
>>> just cause ongoing confusion
>> In don't really see how this can cause confusion!
>
> So, when someone goes and runs a WSGI application directly against you
> WSGIish web server interface which you still insist you can describe
> as being WSGI and it fails because the write() method isn't
> implemented what is your answr going to be? If something is going to
> use WSGI name it should implement the full WSGI specification.
>

To make people happy, I can just have the default implementation include
the required middleware by default.

>>> like you did with when you felt you could
>>> reuse the 'mod_wsgi' name for your nginx
>> In fact the first thing I did during code refactoring was to rename it
>> to ngx_http_wsgi_module.
>
> The mod_wsgi name is still used all through
> http://wiki.nginx.org/NginxNgxWSGIModule that I can tell.
>

I still have to update it.


Manlio
_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Graham Dumpleton-2
On 9 April 2010 22:15, Manlio Perillo <[hidden email]> wrote:

> Graham Dumpleton ha scritto:
>> [...]
>>> But since the write callable **can** be implemented in a middleware
>>> (using greenlets) and since middlewares *can* be configured inside WSGI
>>> gateway, implementations can still claim to be WSGI 1.0 conformant.
>>
>> Then only the higher level middleware adapter can even claim to be
>> WSGI compliant and deserve to use the WSGI name.
>
> Since the middleware is executed inside WSGI gateway, and the gateway
> can be configured to always execute some middleware, the final
> application will simply have at disposal a WSGI conformant write callable.

Then it isn't really a middleware at all then, but a part of your
overall solution. So long as only the complete solution is exposed and
is WSGI compliant then fine. But if it is going to be layered in any
way such that lower level layers can be used in their own right, then
the lower level layers shouldn't really be said to be WSGI if they
don't implement full WSGI specification. As much as we all have our
complaints about WSGI specification, it is what it is and is all we
have right now.

Graham

>> Any underlying
>> abstraction you use at the web server interface isn't WSGI and by
>> rights should be called something else so there is no confusion and
>> also shouldn't use 'wsgi' keys in its environ dictionary. Have your
>> high level middleware do a completely remapping of names as
>> appropriate.
>>
>
> This will add useless overhead.
>
>>>> Why don't you given it all a completely different name else you will
>>>> just cause ongoing confusion
>>> In don't really see how this can cause confusion!
>>
>> So, when someone goes and runs a WSGI application directly against you
>> WSGIish web server interface which you still insist you can describe
>> as being WSGI and it fails because the write() method isn't
>> implemented what is your answr going to be? If something is going to
>> use WSGI name it should implement the full WSGI specification.
>>
>
> To make people happy, I can just have the default implementation include
> the required middleware by default.
>
>>>> like you did with when you felt you could
>>>> reuse the 'mod_wsgi' name for your nginx
>>> In fact the first thing I did during code refactoring was to rename it
>>> to ngx_http_wsgi_module.
>>
>> The mod_wsgi name is still used all through
>> http://wiki.nginx.org/NginxNgxWSGIModule that I can tell.
>>
>
> I still have to update it.
>
>
> Manlio
>
_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Manlio Perillo-3
Graham Dumpleton ha scritto:

> On 9 April 2010 22:15, Manlio Perillo <[hidden email]> wrote:
>> Graham Dumpleton ha scritto:
>>> [...]
>>>> But since the write callable **can** be implemented in a middleware
>>>> (using greenlets) and since middlewares *can* be configured inside WSGI
>>>> gateway, implementations can still claim to be WSGI 1.0 conformant.
>>> Then only the higher level middleware adapter can even claim to be
>>> WSGI compliant and deserve to use the WSGI name.
>> Since the middleware is executed inside WSGI gateway, and the gateway
>> can be configured to always execute some middleware, the final
>> application will simply have at disposal a WSGI conformant write callable.
>
> Then it isn't really a middleware at all then, but a part of your
> overall solution.

It is just that the gateway has support to direct execution of
middlewares, since this make the implementation more flexible.

> So long as only the complete solution is exposed and
> is WSGI compliant then fine. But if it is going to be layered in any
> way such that lower level layers can be used in their own right, then
> the lower level layers shouldn't really be said to be WSGI if they
> don't implement full WSGI specification. As much as we all have our
> complaints about WSGI specification, it is what it is and is all we
> have right now.
>

By the way, as a matter of curiosity.
WSGI 1.0 states:

"""The start_response callable must return a write(body_data) callable
that takes one positional parameter: a string to be written as part of
the HTTP response body. (Note: the write() callable is provided only to
support certain existing frameworks' imperative output APIs; it should
not be used by new applications or frameworks if it can be avoided. See
the Buffering and Streaming section for more details.)"""


There is nothing that prevents the write callable to raise an exception.

Of course an implementation that always raise a NotImplementedError is
going to be useless (for applications that require the write callable),
but it seems to me that such an implementation can still claim to
conform to WSGI 1.0.

> [...]

Manlio
_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

René Dudfield
On Fri, Apr 9, 2010 at 1:46 PM, Manlio Perillo <[hidden email]> wrote:

By the way, as a matter of curiosity.
WSGI 1.0 states:

"""The start_response callable must return a write(body_data) callable
that takes one positional parameter: a string to be written as part of
the HTTP response body. (Note: the write() callable is provided only to
support certain existing frameworks' imperative output APIs; it should
not be used by new applications or frameworks if it can be avoided. See
the Buffering and Streaming section for more details.)"""


There is nothing that prevents the write callable to raise an exception.

Of course an implementation that always raise a NotImplementedError is
going to be useless (for applications that require the write callable),
but it seems to me that such an implementation can still claim to
conform to WSGI 1.0.


Agreed.

_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Gustavo Narea
In reply to this post by Manlio Perillo-3
Hello,

Maybe I'm missing something obvious, but if the gateway doesn't support
applications that return write() callables, then it's not WSGI.

A callable that raises an exception does not even count. It's obvious
that they must not raise exceptions -- Then what's the point of
providing the callable?

That said, I *think* it might be OK to disable support for the write()
callable *optionally* on a per application basis. For example, the
gateway could look at the "requires_write" attribute of the application
callable, if any:
"""
def wsgi_app(environ, start_response):
    # ... process the request and return a response....

wsgi_app.requires_write = False
"""

That way, applications which don't use the write() callable can let your
gateway know and thus it won't pass one on.

We could even standardize this (at wsgi.org) so that any WSGI middleware
which wraps an application can expose the "requires_write" attribute of
the wrapped application... As long as such a middleware doesn't use
write() either.

On the other hand, I would avoid using "middleware" in this context for
something specific to your implementation as people will believe it's a
proper WSGI middleware. It'd certainly be *middle*ware, but I'd use
something that is not confusing/misleading, like "filter". This is just
a suggestion.

Cheers,

--
Gustavo Narea <xri://=Gustavo>.

_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com
Reply | Threaded
Open this post in threaded view
|

Re: [ANN] twsgi: asynchronous WSGI implementation for Twisted Web

Manlio Perillo-3
Gustavo Narea ha scritto:
> Hello,
>
> Maybe I'm missing something obvious, but if the gateway doesn't support
> applications that return write() callables, then it's not WSGI.
>
> A callable that raises an exception does not even count. It's obvious
> that they must not raise exceptions -- Then what's the point of
> providing the callable?
>

Nothing is obvious in an official specification ;-).

The reason I choose to not completely remove the write callable is
because it will raise a nice error message if someone even try to use my
implementation to execute a WSGI application that requires the write
callable.

Moreover some middlewares or applications may assume the write callable
exists and the value returned by start_response is not None, even if it
is never used.


> That said, I *think* it might be OK to disable support for the write()
> callable *optionally* on a per application basis. For example, the
> gateway could look at the "requires_write" attribute of the application
> callable, if any:
> """
> def wsgi_app(environ, start_response):
>     # ... process the request and return a response....
>
> wsgi_app.requires_write = False
> """
>
> That way, applications which don't use the write() callable can let your
> gateway know and thus it won't pass one on.
>

The problem is that applications that requires the write callable, are
not aware of this extension.

This is really a no problem, IMHO.
If you try to execute an application, and you get a NotImplementedError
extension, then you *know* that write callable is required.

Then, you just configure the WSGI gateway to use the required adapter.
See http://bitbucket.org/mperillo/txwsgi/src/tip/doc/examples/demo_write.py
for a pratical example using txwsgi.

With ngx_http_wsgi_module, you just have to add a
    wsgi_middleware  txwsgi.greenlet write_adapter;
directive in Nginx configuration file.

> We could even standardize this (at wsgi.org) so that any WSGI middleware
> which wraps an application can expose the "requires_write" attribute of
> the wrapped application... As long as such a middleware doesn't use
> write() either.
>
> On the other hand, I would avoid using "middleware" in this context for
> something specific to your implementation as people will believe it's a
> proper WSGI middleware.

Yes.
I now use the term "adapter".


Regards   Manlio
_______________________________________________
Web-SIG mailing list
[hidden email]
Web SIG: http://www.python.org/sigs/web-sig
Unsubscribe: http://mail.python.org/mailman/options/web-sig/lists%40nabble.com