WSGI: the good and the bad

June 19, 2006

WSGI is the Python 'Web Server Gateway Interface', which is a standard interface between web servers and Python web applications. The idea is that you write your app as a WSGI app, then glue it to the web interfaces of your choice: CGI-BIN, SCGI, a standalone testing web server, whatever. The WSGI stuff encourages a stacking model, where modular middleware can be transparently inserted above applications to handle various more or less generic things.

(Ian Bicking gives examples of a bunch of WSGI middleware here.)

A while back I converted DWiki into a WSGI application, and in the process I built up some opinions about the good and the bad of of WSGI.

The good: the ideas. A generic execution environment for web apps is very nice, and the 'stack of simple pieces' approach to apps is a powerful and addictive idea. Plus, WSGI gateways are relatively easy to write, and for apps the interface is pretty simple.

The bad: the complex implementation, which imposes what I call the 'WSGI tax'.

The WSGI tax exists because WSGI had to fit into several existing web server environments, all different, in order to get people to adopt it. To cope with all of them, the full WSGI protocol has a bunch of complex requirements, and general WSGI servers (including all middleware, since it acts as a server for the layer below it) has to support all of them. Not only does this require a pile of cookie-cutter code in each middleware component, but the requirements significantly complicate what you can do when.

I really like the idea of stackable little bits, and I've been very happy with using it heavily in the post-conversion DWiki. But the WSGI tax is too much for me, so DWiki uses a much simpler internal protocol for its stackable layers and appears as monolithic WSGI app to the outside world.

(For scale, a typical DWiki stackable layer is ten to twenty lines of Python. The smallest is three lines, not counting the def; another is five.)

Comments on this page:

From at 2006-06-19 12:26:18:

Have you considered phrasing your stackable pieces as WSGI with a decorator? While raw WSGI can be a little tedious at times (though really only a little in my experience), it should also be entirely possible to resolve this with library elements while still sticking to the WSGI interface. -- Ian Bicking

By cks at 2006-06-19 13:39:37:

The problems I see with decorators (and sort of why I haven't tried it) is that there are several different places my layers want to take action in, and some of them want to act at multiple places:

  • before the next layer down acts, possibly returning its own result and aborting further processing.
  • after the next layer down has returned a response, possibly replacing it.
  • both before and after the next layer down acts, possibly capturing the entire response.

The last one especially seems troublesome, because as far as I can see you'd have to have multiple call points in the generic WSGI processing. Multiple call points also makes layers harder to write, because they have to do something special to preserve local variables across the call points.

(And with WSGI you have two 'after' cases: after the headers and the first line of body output have been generated, and after all of the body output has been generated.)

With a simpler request object/response object interface, I can write layers that just look like:

def TimeLayer(next, request):
  t0 = time.time()
  resp = next(request)
  td = time.time() - t0
  request.log("Time: %.3g sec" % td)

I'm not sure how to even do this in a WSGI approach. I suppose I'd have to dump the start time in the WSGI environment, then pull it out later in the post-entire-response hook.

By cks at 2006-06-19 13:40:44:

Quick postscript to my previous comment: the TimeLayer routine needs a 'return resp' at the end. Whoops.

Written on 19 June 2006.
« Weekly spam summary on June 17th, 2006
An odd choice of hostname »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Mon Jun 19 01:24:22 2006
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.