Phillip Eby posted another revision of the Web Server Gateway Interface (WSGI) spec, and it's pretty much ready to be proposed as a PEP and be discussed more widely.
So I was thinking about WSGI middleware (extending my previous thoughts). WSGI specifies a fairly simple interface between a "server" and an "application". The application in turn can be a server to another application; thus it would be middleware. It would be cool to implement Webware as a stack of such middleware: each piece would be small, easily understood and debugged; parts could be shared with others (or taken from other projects); smaller pieces are easier to understand, and the code flow is very specific. If I was to take everything Webware does now and turn it into these middleware components, this is what I think I'd get:
1. The AppServer. This is a threaded server that accepts connections (both a special FastCGI-like protocol and HTTP), spawns a thread for the request, and passes the request on.
2. Configuration handler. I don't know exactly where this comes in, but I want to configure all these pieces together, but also include URL-specific configuration. So the configuration has to be involved in this chain of middleware.
3. An exception catcher. This will catch any exceptions in the application, log them, email them, provide post-mortem debugging information, display a pretty traceback, etc.
4. A session handler. This will look for any session variables, and create a session object if needed. It will put the session object in the environ dictionary (webkit.session).
5. A URL parser/resource finder. This is URLParser in Webware CVS. It looks on the disk to find a file (as well as looking at other hooks). Once it finds a file or some resource, it finds a factory (based on extension or some other metadata) and uses the factory to create an application.
6. A ServletFactory which talks WSGI. This moves things like the creation of HTTPRequest further back in the process.
The interesting part of this is that a lot of this isn't very Webware-specific at all. Step 6 is very specific to Webware, but the rest isn't. Pieces can also be swapped out. For instance, I'd actually like to change this, as I think Webware spawns a thread too early -- I suspect threads and sockets interact poorly on some platforms, causing the occasional lockup. Redhat and FreeBSD seem to have problems. So I'd swap out #1 for:
1a. An async server. Either Medusa or Twisted. Medusa is smaller, Twisted better; once the Twisted stuff I'm interested is available separately (which is planned), then it would probably be an easier choice.
1b. A threading middleware. It takes the async request that 1a generates, and uses a threadpool to make it multithreaded, handling whatever buffering or interaction it needs to do.
There's other pieces that can be recombined. For instance, the URLParser could redirect the request to any WSGI application, not just Webware servlets. The exception catcher could be developed separately, and should work just fine with any stack. Each piece could reasonably have multiple implementations. This seems like a good way to compose a framework.
And, don't forget that WebWare users would also be able to switch out 1, 1a, and 1b for something else altogether, like mod_python or PEAK's FastCGI runner, once they support WSGI.
Of course, that's assuming that the other pieces in your stack support a multi-process execution model as well as the single process, multi-thread modes. But even if they don't, the web server can be any single-process multi-thread WSGI server or gateway.
# Phillip J. Eby
Webware stuff generally expects a single-process, multi-threaded model. But most of those things could be made neutral, though there are a lot of Webware applications that assume a multi-threaded environment (e.g., they store global information in global variables).# Ian Bicking
The python threading model is broken, it's about time we fix it:
(I know that stackless implements part of the csp model, but stackless has lots of other stuff I don't want, and stackless is not CPython that is what I want to use)# Uriel